#!/bin/bash
script_version="v2025-09-18"
check_bash(){
current_bash_version=$(bash --version|head -n 1|awk '{for(i=1;i<=NF;i++) if ($i ~ /^[0-9]+\.[0-9]+(\.[0-9]+)?/) print $i}')
major_version=$(echo "$current_bash_version"|cut -d'.' -f1)
minor_version=$(echo "$current_bash_version"|cut -d'.' -f2)
if [ "$major_version" -lt 4 ]||{ [ "$major_version" -eq 4 ]&&[ "$minor_version" -lt 3 ];};then
echo "ERROR: Bash version is $current_bash_version lower than 4.3!"
echo "Tips: Run the following script to automatically upgrade Bash."
echo "bash <(curl -sL https://raw.githubusercontent.com/xykt/NetQuality/main/ref/upgrade_bash.sh)"
exit 0
fi
}
check_bash
Font_B="\033[1m"
Font_D="\033[2m"
Font_I="\033[3m"
Font_U="\033[4m"
Font_Black="\033[30m"
Font_Red="\033[31m"
Font_Green="\033[32m"
Font_Yellow="\033[33m"
Font_Blue="\033[34m"
Font_Purple="\033[35m"
Font_Cyan="\033[36m"
Font_White="\033[37m"
Back_Black="\033[40m"
Back_Red="\033[41m"
Back_Green="\033[42m"
Back_Yellow="\033[43m"
Back_Blue="\033[44m"
Back_Purple="\033[45m"
Back_Cyan="\033[46m"
Back_White="\033[47m"
Font_Suffix="\033[0m"
Font_LineClear="\033[2K"
Font_LineUp="\033[1A"
declare ADLines
declare -A aad
declare IP=""
declare IPhide
declare fullIP=0
declare YY="cn"
declare is_dep=1
declare is_nexttrace=1
declare is_speedtest=1
declare -A bgp
declare -A getbgp
declare -A getnat
declare -A gettcp
declare -A conn
declare -A casn
declare -A corg
declare -A ctarget
declare -A ctier1
declare -A cupstream
declare -A pcode
declare -A pshort
declare -A pname
declare -A pdm
declare -A presu
declare -A pavg
declare -A pout
declare -A iperfresu
declare -A icity
declare -A idm
declare -A iportl
declare -A iportu
declare -A iresu
declare -A isout
declare -A ipout
declare -A iavg
declare -A scity
declare -A spv
declare -A sid
declare -A sout
declare -A sresu
declare -A rww
declare -A rcn
declare -A routww
declare -A routcn
declare rgia=0
declare -A AS_MAPPING
declare -A rmcode
declare -A rmresu
declare rmtestnum
declare -A rmallasn
declare -A rmallgeo
declare -A rmmaxhop
declare -A rmcnhop
declare -A rmcn
declare -A rmww
declare rmgia=0
declare IPV4
declare IPV6
declare IPV4check=1
declare IPV6check=1
declare IPV4work=0
declare IPV6work=0
declare ERRORcode=0
declare shelp
declare -A swarn
declare -A sinfo
declare -A shead
declare -A sbgp
declare -A slocal
declare -A sconn
declare -A sdelay
declare -A sroute
declare -A siperf
declare -A sspeedtest
declare -A stail
declare ibar=0
declare bar_pid
declare ibar_step=0
declare main_pid=$$
declare PADDING=""
declare useNIC=""
declare usePROXY=""
declare CurlARG=""
declare UA_Browser
declare rawgithub
declare ISO3166
declare display_max_len=80
declare mode_ping=0
declare mode_route=0
declare mode_route_pv=""
declare mode_low=0
declare mode_json=0
declare mode_no=0
declare mode_yes=0
declare mode_skip=""
declare mode_menu=0
declare mode_output=0
declare mode_privacy=0
declare ping_test_count=10
declare pingww_test_count=12
declare usesudo="sudo"
declare netdata
shelp_lines=(
"NETWORK QUALITY CHECK SCRIPT 网络质量体检脚本"
"Interactive Interface:  bash <(curl -sL https://Net.Check.Place) -EM"
"交互界面：              bash <(curl -sL https://Net.Check.Place) -M"
"Parameters 参数运行: bash <(curl -sL https://Net.Check.Place) [-4] [-6] [-f] [-h] [-j] [-l language] [-n] [-y] [-E] [-L] [-M] [-P] [-R province] [-S chapters]"
"            -4                             Test IPv4                                  测试IPv4"
"            -6                             Test IPv6                                  测试IPv6"
"            -f                             Show full IP on reports                    报告展示完整IP地址"
"            -h                             Help information                           帮助信息"
"            -j                             JSON output                                JSON输出"
"            -l cn|en                       Specify script language                    指定报告语言"
"            -n                             No OS or dependencies check                跳过系统检测及依赖安装"
"            -o /path/to/file.ansi          Output ANSI report to file                 输出ANSI报告至文件"
"               /path/to/file.json          Output JSON result to file                 输出JSON结果至文件"
"               /path/to/file.anyother      Output plain text report to file           输出纯文本报告至文件"
"            -p                             Privacy mode - no generate report link     隐私模式：不生成报告链接"
"            -y                             Install dependencies without interupt      自动安装依赖"
"            -E                             Specify English Output                     指定英文输出"
"            -L                             Low data mode                              低数据模式（跳过测速环节）"
"            -M                             Run with Interactive Interface             交互界面方式运行"
"            -P                             Ping mode                                  三网延迟模式"
"            -R [Province]                  Route mode [Specify Province]              三网完整路由模式[可选指定省份]"
"            -S 1234567                     Skip sections by number                    跳过相应章节")
shelp=$(printf "%s\n" "${shelp_lines[@]}")
set_language(){
case "$YY" in
"en"|"jp"|"es"|"de"|"fr"|"ru"|"pt")swarn[1]="ERROR: Unsupported parameters!"
swarn[2]="ERROR: IP address format error!"
swarn[3]="ERROR: Dependent programs are missing. Please run as root or install sudo!"
swarn[4]="ERROR: Parameter -4 conflicts with -i or -6!"
swarn[6]="ERROR: Parameter -6 conflicts with -i or -4!"
swarn[9]="ERROR: It is not allowed to skip all funcions!"
swarn[10]="ERROR: Output file already exist!"
swarn[11]="ERROR: Output file is not writable!"
swarn[21]="ERROR: Wrong province code or name!"
swarn[40]="ERROR: IPv4 is not available!"
swarn[60]="ERROR: IPv6 is not available!"
sinfo[bgp]="Checking BGP database"
sinfo[lbgp]=21
sinfo[neighbor]="Checking Active Neighbors"
sinfo[lneighbor]=25
sinfo[nat]="Checking NAT Type"
sinfo[lnat]=17
sinfo[tcp]="Checking TCP Settings"
sinfo[ltcp]=21
sinfo[delay]="Checking China Mainland TCP Delay"
sinfo[ldelay]=33
sinfo[route]="Checking Route to China Mainland"
sinfo[lroute]=32
sinfo[moderoute]="Checking Route details to Specified Province"
sinfo[lmoderoute]=44
sinfo[speedtest]="Checking Speedtest of China "
sinfo[lspeedtest]=28
sinfo[iperf]="Checking Global Transfer of "
sinfo[liperf]=28
sinfo[delayww]="Checking Global TCP Delay"
sinfo[ldelayww]=25
shead[title]="NET QUALITY CHECK REPORT: "
shead[ver]="Version: $script_version"
shead[bash]="bash <(curl -sL https://Check.Place) -EN"
shead[git]="https://github.com/xykt/NetQuality"
shead[time]=$(date -u +"Report Time: %Y-%m-%d %H:%M:%S UTC")
shead[ltitle]=26
shead[ptime]=$(printf '%11s' '')
sbgp[title]="1. BGP Information (${Font_I}BGP.TOOLS & HE.NET$Font_Suffix)"
sbgp[ipinfo]="Reg Info:           "
sbgp[country]="Region:             "
sbgp[address]="Address:            "
sbgp[geofeed]="GeoFeed:            "
sbgp[date]="Reg/Mod Date:       "
sbgp[neighbor]="Active Neighbors:   "
slocal[title]="2. Local Status"
slocal[nat]="NAT Type:           "
slocal[tcpcc]="Congestion Control: "
slocal[qdisc]="Queue Discipline:   "
slocal[rmem]="TCP Receive Buffer: "
slocal[wmem]="TCP Send Buffer:    "
slocal[port]="Port: "
slocal[mapping]="Mapping: "
slocal[filter]="Filter: "
slocal[hairpin]="Hairpin: "
slocal[m0]="${Font_Green}Independent  $Font_Suffix"
slocal[m1]="${Font_Red}Dependent    $Font_Suffix"
slocal[f1]="${Font_Green}Independent      $Font_Suffix"
slocal[f2]="${Font_Yellow}AddressDependent $Font_Suffix"
slocal[f3]="${Font_Red}PortDependent    $Font_Suffix"
slocal[p0]="${Font_Yellow}Random    $Font_Suffix"
slocal[p1]="${Font_Green}Preserve  $Font_Suffix"
slocal[h0]="${Font_Green}Yes$Font_Suffix"
slocal[h1]="${Font_Red}No$Font_Suffix"
slocal[open]="$Back_Green$Font_White$Font_B Open Without NAT $Font_Suffix"
slocal[full]="$Font_White$Font_B Full Cone $Font_Suffix"
slocal[rest]="$Back_Yellow$Font_White$Font_B Restricted Cone $Font_Suffix"
slocal[portrest]="$Back_Yellow$Font_White$Font_B Port Restricted Cone $Font_Suffix"
slocal[symm]="$Back_Red$Font_White$Font_B Symmetric $Font_Suffix"
slocal[fail]="$Back_Red$Font_White$Font_B Checking Error $Font_Suffix"
slocal[firewall]="$Back_Yellow$Font_White$Font_B Firewall $Font_Suffix"
slocal[block]="$Back_Red$Font_White$Font_B Connection Failed $Font_Suffix"
slocal[unknown]="$Back_Yellow$Font_White$Font_B Unknown NAT Type $Font_Suffix"
sconn[title]="3. Connectivity ($Back_Green$Font_White$Font_B*$Font_Suffix$Font_I=Tier1 $Font_Suffix$Back_Yellow$Font_White$Font_B*$Font_Suffix$Font_I=Non-Tier1 $Font_Suffix$Font_U*$Font_Suffix$Font_I=Upstream$Font_Suffix)"
sconn[ix]="IXPs Counts: "
sconn[upstreams]="Upstreams Counts: "
sconn[peers]="Peers Counts: "
sdelay[title]="4. China Mainland TCP Delay (${Font_I}CT|CU|CM Step=80ms$Font_Suffix)      "
sdelay[pingmode]="$(printf '%8s'|tr ' ' '*')China Telecom$(printf '%13s'|tr ' ' '*')China Unicom$(printf '%14s'|tr ' ' '*')China Mobile$(printf '%8s'|tr ' ' '*')"
sroute[title]="5. Route to China Mainland (May vary with network congestion)"
sroute[ct]="CTel"
sroute[cu]="CUni"
sroute[cm]="CMob"
sroute[bj]="BJ "
sroute[sh]="SH "
sroute[gz]="GZ "
sroute[tcp]="TCP:  "
sroute[udp]="UDP:  "
sspeedtest[title]="6. CN NetSpeed $Font_I${Font_U}Send$Font_Suffix ${Font_I}Delay ${Font_U}Receive$Font_Suffix ${Font_I}Delay$Font_Suffix||Unit: ${Font_U}Mbps$Font_Suffix$Font_I ms  ${Font_U}Send$Font_Suffix ${Font_I}Delay ${Font_U}Receive$Font_Suffix ${Font_I}Delay$Font_Suffix"
siperf[title]="7. Global Network   $Font_I${Font_U}Send$Font_Suffix ${Font_I}Retr ${Font_U}Recv$Font_Suffix ${Font_I}Retr$Font_Suffix||Unit: ms ${Font_U}Mbps$Font_Suffix$Font_I Delay ${Font_U}Send$Font_Suffix ${Font_I}Retr ${Font_U}Recv$Font_Suffix ${Font_I}Retr$Font_Suffix"
siperf[send]=" Send"
siperf[recv]=" Receive"
stail[stoday]="Network Checks Today: "
stail[stotal]="; Total: "
stail[thanks]=". Thanks for running xy scripts!"
stail[link]="${Font_I}Report Link: $Font_U"
;;
"cn")swarn[1]="错误：不支持的参数！"
swarn[2]="错误：IP地址格式错误！"
swarn[3]="错误：未安装依赖程序，请以root执行此脚本，或者安装sudo命令！"
swarn[4]="错误：参数-4与-i/-6冲突！"
swarn[6]="错误：参数-6与-i/-4冲突！"
swarn[9]="错误: 不允许跳过所有功能！"
swarn[10]="错误：输出文件已存在！"
swarn[11]="错误：输出文件不可写！"
swarn[21]="错误: 错误的省份名称或代码！"
swarn[40]="错误：IPV4不可用！"
swarn[60]="错误：IPV6不可用！"
sinfo[bgp]="正在检测BGP数据库 "
sinfo[lbgp]=18
sinfo[neighbor]="正在检测活跃邻居 "
sinfo[lneighbor]=17
sinfo[nat]="正在检测NAT类型 "
sinfo[lnat]=16
sinfo[tcp]="正在检测TCP设置 "
sinfo[ltcp]=16
sinfo[delay]="正在检测大陆三网TCP大包延迟"
sinfo[ldelay]=27
sinfo[route]="正在检测大陆三网回程线路"
sinfo[lroute]=24
sinfo[moderoute]="正在检测TCP回程详细路由"
sinfo[lmoderoute]=23
sinfo[speedtest]="正在检测三网Speedtest之"
sinfo[lspeedtest]=23
sinfo[iperf]="正在检测国际互连："
sinfo[liperf]=18
sinfo[delayww]="正在检测国际互连TCP大包延迟"
sinfo[ldelayww]=27
shead[title]="网络质量体检报告："
shead[ver]="脚本版本：$script_version"
shead[bash]="bash <(curl -sL https://Check.Place) -N"
shead[git]="https://github.com/xykt/NetQuality"
shead[time]=$(TZ="Asia/Shanghai" date +"报告时间：%Y-%m-%d %H:%M:%S CST")
shead[ltitle]=18
shead[ptime]=$(printf '%12s' '')
sbgp[title]="一、BGP信息（${Font_I}BGP.TOOLS & HE.NET$Font_Suffix）"
sbgp[ipinfo]="注册信息：          "
sbgp[country]="地区：              "
sbgp[address]="地址：              "
sbgp[geofeed]="地理数据供给：      "
sbgp[date]="注册/修改日期：     "
sbgp[neighbor]="活跃邻居：          "
slocal[title]="二、本地策略"
slocal[nat]="NAT类型：        "
slocal[tcpcc]="TCP拥塞控制算法："
slocal[qdisc]="队列调度算法：   "
slocal[rmem]="TCP接收缓冲区（rmem）："
slocal[wmem]="TCP发送缓冲区（wmem）："
slocal[port]="端口行为："
slocal[mapping]="映射行为："
slocal[filter]="过滤行为："
slocal[hairpin]="环回："
slocal[m0]="$Font_Green独立映射  $Font_Suffix"
slocal[m1]="$Font_Red依赖映射  $Font_Suffix"
slocal[f1]="$Font_Green端点独立过滤 $Font_Suffix"
slocal[f2]="$Font_Yellow地址依赖过滤 $Font_Suffix"
slocal[f3]="$Font_Red端口依赖过滤 $Font_Suffix"
slocal[p0]="$Font_Yellow端口随机  $Font_Suffix"
slocal[p1]="$Font_Green端口保留  $Font_Suffix"
slocal[h0]="$Font_Green支持$Font_Suffix"
slocal[h1]="$Font_Red不支持$Font_Suffix"
slocal[open]="$Back_Green$Font_White$Font_B 开放网络无NAT $Font_Suffix"
slocal[full]="$Font_White$Font_B 全锥形 $Font_Suffix"
slocal[rest]="$Back_Yellow$Font_White$Font_B 受限锥形 $Font_Suffix"
slocal[portrest]="$Back_Yellow$Font_White$Font_B 端口受限锥形 $Font_Suffix"
slocal[symm]="$Back_Red$Font_White$Font_B 对称型 $Font_Suffix"
slocal[fail]="$Back_Red$Font_White$Font_B 检测错误 $Font_Suffix"
slocal[firewall]="$Back_Yellow$Font_White$Font_B 防火墙 $Font_Suffix"
slocal[block]="$Back_Red$Font_White$Font_B 连接失败 $Font_Suffix"
slocal[unknown]="$Back_Yellow$Font_White$Font_B 未知NAT类型 $Font_Suffix"
sconn[title]="三、接入信息（$Back_Green$Font_White$Font_B*$Font_Suffix$Font_I=Tier1 $Font_Suffix$Back_Yellow$Font_White$Font_B*$Font_Suffix$Font_I=非Tier1 $Font_Suffix$Font_U*$Font_Suffix$Font_I=上游$Font_Suffix）"
sconn[ix]="互联网交换点接入数："
sconn[upstreams]="上游数量："
sconn[peers]="对等互联数量："
sdelay[title]="四、三网TCP大包延迟（$Font_I依次为电信|联通|移动 Step=80ms$Font_Suffix） "
sdelay[pingmode]="$(printf '%12s'|tr ' ' '*')电 信$(printf '%21s'|tr ' ' '*')联 通$(printf '%21s'|tr ' ' '*')移 动$(printf '%11s'|tr ' ' '*')"
sroute[title]="五、三网回程路由（$Font_I线路可能随网络负载动态变化$Font_Suffix）"
sroute[ct]="电信"
sroute[cu]="联通"
sroute[cm]="移动"
sroute[bj]="北京"
sroute[sh]="上海"
sroute[gz]="广州"
sroute[tcp]="TCP："
sroute[udp]="UDP："
sspeedtest[title]="六、国内测速   $Font_I$Font_U发送$Font_Suffix  $Font_I延迟    $Font_U接收$Font_Suffix  $Font_I延迟$Font_Suffix||单位：${Font_U}Mbps$Font_Suffix$Font_I ms  $Font_U发送$Font_Suffix  $Font_I延迟    $Font_U接收$Font_Suffix  $Font_I延迟$Font_Suffix"
siperf[title]="七、国际互连   $Font_I延迟 $Font_U发送$Font_Suffix $Font_I重传 $Font_U接收$Font_Suffix $Font_I重传$Font_Suffix||单位：ms ${Font_U}Mbps$Font_Suffix$Font_I  延迟 $Font_U发送$Font_Suffix $Font_I重传 $Font_U接收$Font_Suffix $Font_I重传$Font_Suffix"
siperf[send]="之发送"
siperf[recv]="之接收"
stail[stoday]="今日网络检测量："
stail[stotal]="；总检测量："
stail[thanks]="。感谢使用xy系列脚本！"
stail[link]="$Font_I报告链接：$Font_U"
;;
*)echo -ne "ERROR: Language not supported!"
esac
}
countRunTimes(){
local RunTimes=$(curl $CurlARG -s --max-time 10 "https://hits.xykt.de/net?action=hit" 2>&1)
stail[today]=$(echo "$RunTimes"|jq '.daily')
stail[total]=$(echo "$RunTimes"|jq '.total')
}
show_progress_bar(){
show_progress_bar_ "$@" 1>&2
}
show_progress_bar_(){
local bar="\u280B\u2819\u2839\u2838\u283C\u2834\u2826\u2827\u2807\u280F"
local n=${#bar}
while sleep 0.1;do
if ! kill -0 $main_pid 2>/dev/null;then
echo -ne ""
exit
fi
echo -ne "\r$Font_Cyan$Font_B[$IP]# $1$Font_Cyan$Font_B$(printf '%*s' "$2" ''|tr ' ' '.') ${bar:ibar++*6%n:6} $(printf '%02d%%' $ibar_step) $Font_Suffix"
done
}
kill_progress_bar(){
kill "$bar_pid" 2>/dev/null&&echo -ne "\r"
}
install_dependencies(){
local is_dep=1
local is_nexttrace=1
local is_speedtest=1
local is_stun=1
if [ "$(uname)" == "Darwin" ]||[ $(id -u) -eq 0 ];then
usesudo=""
fi
if ! jq --version >/dev/null 2>&1||! curl --version >/dev/null 2>&1||! command -v convert >/dev/null 2>&1||! command -v mtr >/dev/null 2>&1||! command -v iperf3 >/dev/null 2>&1||! command -v stun >/dev/null 2>&1||(! command -v stun >/dev/null 2>&1&&! command -v pkg >/dev/null 2>&1&&[[ "$(uname)" != "Darwin" ]])||(! command -v free >/dev/null 2>&1&&[[ "$(uname)" != "Darwin" ]]);then
is_dep=0
fi
if ! command -v nexttrace >/dev/null 2>&1;then
is_nexttrace=0
fi
if ! command -v speedtest >/dev/null 2>&1;then
is_speedtest=0
fi
if ! command -v stun >/dev/null 2>&1&&(command -v apk >/dev/null 2>&1||command -v yum >/dev/null 2>&1||command -v zypper >/dev/null 2>&1||command -v xbps-install >/dev/null 2>&1||command -v pacman >/dev/null 2>&1);then
is_stun=0
fi
if [[ $is_dep -eq 0 || $is_nexttrace -eq 0 || $is_speedtest -eq 0 ]];then
echo -e "Lacking necessary dependencies."
[[ $is_dep -eq 0 ]]&&echo -e "Packages $Font_I${Font_Cyan}jq curl imagemagick mtr iperf3 stun bc$Font_Suffix will be installed using ${Font_Green}package manager$Font_Suffix."
[[ $is_nexttrace -eq 0 ]]&&echo -e "Application $Font_I${Font_Cyan}nexttrace$Font_Suffix will be installed via $Font_Green${Font_I}curl nxtrace.org/nt |bash$Font_Suffix by ${Font_U}https://www.nxtrace.org/$Font_Suffix official."
[[ $is_speedtest -eq 0 ]]&&echo -e "Application $Font_I${Font_Cyan}speedtest$Font_Suffix will be installed using ${Font_B}Speedtest.net$Font_Suffix official installation method ${Font_U}https://www.speedtest.net/apps/cli$Font_Suffix."
if [[ $mode_yes -eq 0 ]];then
prompt=$(printf "Continue? (${Font_Green}y$Font_Suffix/${Font_Red}n$Font_Suffix): ")
read -p "$prompt" choice
case "$choice" in
y|Y|yes|Yes|YES)echo "Continue to execute script..."
;;
n|N|no|No|NO)echo "Script exited."
exit 0
;;
*)echo "Invalid input, script exited."
exit 1
esac
else
echo -e "Detected parameter $Font_Green-y$Font_Suffix. Continue installation..."
fi
if [[ $is_dep -eq 0 ]];then
if [ "$(uname)" == "Darwin" ];then
install_packages "brew" "brew install"
elif [ -f /etc/os-release ];then
. /etc/os-release
if [ $(id -u) -ne 0 ]&&! command -v sudo >/dev/null 2>&1;then
ERRORcode=3
fi
case $ID in
debian)install_packages "apt" "apt-get install -y"
;;
ubuntu|linuxmint)install_packages "apt" "apt-get install -y"
;;
rhel|centos|almalinux|rocky|anolis)if
[ "$(echo $VERSION_ID|cut -d '.' -f1)" -ge 8 ]
then
install_packages "dnf" "dnf install -y"
else
install_packages "yum" "yum install -y"
fi
;;
arch|manjaro)install_packages "pacman" "pacman -S --noconfirm"
;;
alpine)install_packages "apk" "apk add"
;;
fedora)install_packages "dnf" "dnf install -y"
;;
alinux)install_packages "yum" "yum install -y"
;;
suse|opensuse*)install_packages "zypper" "zypper install -y"
;;
void)install_packages "xbps" "xbps-install -Sy"
;;
*)echo "Unsupported distribution: $ID"
exit 1
esac
elif [ -n "$PREFIX" ];then
install_packages "pkg" "pkg install"
else
echo "Cannot detect distribution because /etc/os-release is missing."
exit 1
fi
fi
if [[ $is_nexttrace -eq 0 ]];then
curl -s nxtrace.org/nt|bash
fi
if [[ $is_speedtest -eq 0 ]];then
install_speedtest
fi
if [[ $is_stun -eq 0 ]];then
install_stun
fi
fi
}
install_packages(){
local package_manager=$1
local install_command=$2
case $package_manager in
apt)$usesudo apt update
$usesudo $install_command jq curl imagemagick mtr-tiny iperf3 stun bc procps
;;
dnf)$usesudo $install_command epel-release
$usesudo $package_manager makecache
$usesudo $install_command jq curl ImageMagick mtr iperf3 stun bc procps-ng
;;
yum)$usesudo $install_command epel-release
$usesudo $package_manager makecache
$usesudo $install_command jq curl ImageMagick mtr iperf3 bc procps-ng libstdc++
;;
pacman)$usesudo pacman -Sy
$usesudo $install_command jq curl imagemagick mtr iperf3 bc procps-ng
if command -v paru >/dev/null 2>&1;then
paru -S --noconfirm gcompat
elif command -v yay >/dev/null 2>&1;then
yay -S --noconfirm gcompat
fi
;;
apk)$usesudo apk update
$usesudo $install_command jq curl imagemagick mtr iperf3 bc procps gcompat libstdc++
;;
pkg)$usesudo $package_manager update
$usesudo $package_manager $install_command jq curl imagemagick mtr iperf3 bc procps libstdcxx
;;
brew)eval "$(/opt/homebrew/bin/brew shellenv)"
$install_command jq curl imagemagick mtr iperf3 bc
;;
zypper)$usesudo zypper refresh
$usesudo $install_command jq curl imagemagick mtr iperf3 bc procps libstdc++6
;;
xbps)$usesudo xbps-install -Sy
$usesudo $install_command jq curl imagemagick mtr iperf3 bc procps-ng gcompat libstdc++
esac
}
install_speedtest(){
if [ "$(uname)" == "Darwin" ];then
brew tap teamookla/speedtest
brew update
brew install speedtest --force
elif [ "$(uname)" == "FreeBSD" ];then
$usesudo pkg update&&sudo pkg install -g libidn2 ca_root_nss
freebsd_version=$(freebsd-version|cut -d '-' -f 1)
case $freebsd_version in
12.*)$usesudo pkg add "https://install.speedtest.net/app/cli/ookla-speedtest-1.2.0-freebsd12-x86_64.pkg"
;;
13.*)$usesudo pkg add "https://install.speedtest.net/app/cli/ookla-speedtest-1.2.0-freebsd13-x86_64.pkg"
;;
*)return 1
esac
else
local sys_type=""
local sysarch="$(uname -m)"
case "$sysarch" in
"x86_64"|"x86"|"amd64"|"x64")sys_type="x86_64";;
"i386"|"i686")sys_type="i386";;
"aarch64"|"armv7l"|"armv8"|"armv8l")sys_type="aarch64";;
*)return 1
esac
$usesudo curl -sL -o /usr/bin/speedtest "${rawgithub}main/ref/speedtest/speedtest-$sys_type"
$usesudo chmod +x /usr/bin/speedtest
fi
}
install_stun(){
local arch
local sys_type
arch=$(uname -m)
case "$arch" in
x86_64)if
[[ "$(getconf LONG_BIT)" == "32" ]]
then
sys_type="i386"
else
sys_type="amd64"
fi
;;
aarch64|arm64)sys_type="arm64"
;;
i386|i486|i586|i686)sys_type="i386"
;;
mips64|mips64el)echo "mips64el"
;;
riscv64)echo "riscv64"
;;
*)return 1
esac
$usesudo curl -sL -o /usr/bin/stun "${rawgithub}main/ref/stun/stun_$sys_type"
$usesudo chmod +x /usr/bin/stun
}
declare -A browsers=(
[Chrome]="139.0.7258.128 139.0.7258.67 138.0.7204.185 138.0.7204.170 138.0.7204.159 138.0.7204.102 138.0.7204.100 138.0.7204.51 138.0.7204.49 137.0.7151.122 138.0.7204.35 137.0.7151.121 137.0.7151.105 137.0.7151.104 137.0.7151.57 137.0.7151.55 136.0.7103.116 137.0.7151.40 136.0.7103.113 136.0.7103.92 135.0.7049.117 136.0.7103.48 135.0.7049.114 135.0.7049.86 135.0.7049.42 135.0.7049.41 134.0.6998.167 134.0.6998.119 134.0.6998.117 134.0.6998.37 134.0.6998.35 133.0.6943.128 133.0.6943.100 133.0.6943.59 133.0.6943.53 132.0.6834.162 133.0.6943.35 132.0.6834.160 132.0.6834.112 132.0.6834.110 131.0.6778.267 132.0.6834.83 131.0.6778.264 131.0.6778.204 131.0.6778.139 131.0.6778.109 131.0.6778.71 131.0.6778.69 130.0.6723.119 131.0.6778.33 130.0.6723.116 130.0.6723.71 130.0.6723.60 130.0.6723.58 129.0.6668.103 130.0.6723.44 129.0.6668.100 129.0.6668.72 129.0.6668.60 129.0.6668.42 128.0.6613.122 128.0.6613.121 128.0.6613.115 128.0.6613.113 127.0.6533.122 128.0.6613.36 127.0.6533.119 127.0.6533.100 127.0.6533.74 127.0.6533.72 126.0.6478.185 127.0.6533.57 126.0.6478.183 126.0.6478.128 126.0.6478.116 126.0.6478.114 126.0.6478.61 125.0.6422.176 126.0.6478.56 125.0.6422.144 126.0.6478.36 125.0.6422.142 125.0.6422.114 125.0.6422.77 125.0.6422.76 124.0.6367.210 125.0.6422.60 124.0.6367.208 124.0.6367.201 124.0.6367.156 125.0.6422.41 124.0.6367.155 124.0.6367.119 124.0.6367.92 124.0.6367.63 124.0.6367.61 123.0.6312.124 124.0.6367.60 123.0.6312.122 123.0.6312.106 123.0.6312.105 123.0.6312.60 123.0.6312.58 122.0.6261.131 123.0.6312.46 122.0.6261.129 122.0.6261.128 122.0.6261.112 122.0.6261.111 122.0.6261.71 122.0.6261.69 121.0.6167.189 122.0.6261.57 121.0.6167.187 121.0.6167.186 121.0.6167.162 121.0.6167.160 121.0.6167.140 121.0.6167.86 121.0.6167.85 120.0.6099.227 120.0.6099.225 121.0.6167.75 120.0.6099.224 120.0.6099.218 120.0.6099.216 120.0.6099.200 120.0.6099.199 120.0.6099.129 120.0.6099.110 120.0.6099.109 120.0.6099.62 120.0.6099.56"
[Firefox]="132.0 131.0 130.0 129.0 128.0 127.0 126.0 125.0 124.0 123.0 122.0 121.0 120.0")
generate_random_user_agent(){
local browsers_keys=(${!browsers[@]})
local random_browser_index=$((RANDOM%${#browsers_keys[@]}))
local browser=${browsers_keys[random_browser_index]}
case $browser in
Chrome)local versions=(${browsers[Chrome]})
local version=${versions[RANDOM%${#versions[@]}]}
UA_Browser="Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/$version Safari/537.36"
;;
Firefox)local versions=(${browsers[Firefox]})
local version=${versions[RANDOM%${#versions[@]}]}
UA_Browser="Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:$version) Gecko/20100101 Firefox/$version"
esac
}
check_connectivity(){
local url="https://www.google.com/generate_204"
local timeout=2
local http_code
http_code=$(curl -s -o /dev/null -w "%{http_code}" --connect-timeout "$timeout" "$url" 2>/dev/null)
if [[ $http_code == "204" ]];then
rawgithub="https://github.com/xykt/NetQuality/raw/"
return 0
else
rawgithub="https://testingcf.jsdelivr.net/gh/xykt/NetQuality@"
return 1
fi
}
is_valid_ipv4(){
local ip=$1
if [[ $ip =~ ^([0-9]{1,3}\.){3}[0-9]{1,3}$ ]];then
IFS='.' read -r -a octets <<<"$ip"
for octet in "${octets[@]}";do
if ((octet<0||octet>255));then
IPV4work=0
return 1
fi
done
IPV4work=1
return 0
else
IPV4work=0
return 1
fi
}
is_private_ipv4(){
local ip_address=$1
if [[ -z $ip_address ]];then
return 0
fi
if [[ $ip_address =~ ^10\. ]]||[[ $ip_address =~ ^172\.(1[6-9]|2[0-9]|3[0-1])\. ]]||[[ $ip_address =~ ^192\.168\. ]]||[[ $ip_address =~ ^127\. ]]||[[ $ip_address =~ ^0\. ]]||[[ $ip_address =~ ^22[4-9]\. ]]||[[ $ip_address =~ ^23[0-9]\. ]];then
return 0
fi
return 1
}
get_ipv4(){
local response
local API_NET=("ip.sb" "ping0.cc" "icanhazip.com" "api64.ipify.org" "ifconfig.co" "ident.me")
for p in "${API_NET[@]}";do
response=$(curl $CurlARG -s4 --max-time 8 "$p")
if [[ $? -eq 0 && ! $response =~ error ]];then
IPV4="$response"
break
fi
done
}
hide_ipv4(){
if [[ -n $1 ]];then
IFS='.' read -r -a ip_parts <<<"$1"
IPhide="${ip_parts[0]}.${ip_parts[1]}.*.*"
else
IPhide=""
fi
}
is_valid_ipv6(){
local ip=$1
if [[ $ip =~ ^([0-9a-fA-F]{1,4}:){7}[0-9a-fA-F]{1,4}$ || $ip =~ ^([0-9a-fA-F]{1,4}:){1,7}:$ || $ip =~ ^:([0-9a-fA-F]{1,4}:){1,7}$ || $ip =~ ^([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}$ || $ip =~ ^([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}$ || $ip =~ ^([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}$ || $ip =~ ^([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}$ || $ip =~ ^([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}$ || $ip =~ ^[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})$ || $ip =~ ^:((:[0-9a-fA-F]{1,4}){1,7}|:)$ || $ip =~ ^fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}$ || $ip =~ ^::(ffff(:0{1,4}){0,1}:){0,1}(([0-9]{1,3}\.){3}[0-9]{1,3})$ || $ip =~ ^([0-9a-fA-F]{1,4}:){1,4}:(([0-9]{1,3}\.){3}[0-9]{1,3})$ ]];then
IPV6work=1
return 0
else
IPV6work=0
return 1
fi
}
is_private_ipv6(){
local address=$1
if [[ -z $address ]];then
return 0
fi
if [[ $address =~ ^fe80: ]]||[[ $address =~ ^fc00: ]]||[[ $address =~ ^fd00: ]]||[[ $address =~ ^2001:db8: ]]||[[ $address == ::1 ]]||[[ $address =~ ^::ffff: ]]||[[ $address =~ ^2002: ]]||[[ $address =~ ^2001: ]];then
return 0
fi
return 1
}
get_ipv6(){
local response
local API_NET=("ip.sb" "ping0.cc" "icanhazip.com" "api64.ipify.org" "ifconfig.co" "ident.me")
for p in "${API_NET[@]}";do
response=$(curl $CurlARG -s6k --max-time 8 "$p")
if [[ $? -eq 0 && ! $response =~ error ]];then
IPV6="$response"
break
fi
done
}
hide_ipv6(){
if [[ -n $1 ]];then
local expanded_ip=$(echo "$1"|sed 's/::/:0000:0000:0000:0000:0000:0000:0000:0000:/g'|cut -d ':' -f1-8)
IFS=':' read -r -a ip_parts <<<"$expanded_ip"
while [ ${#ip_parts[@]} -lt 8 ];do
ip_parts+=(0000)
done
IPhide="${ip_parts[0]:-0}:${ip_parts[1]:-0}:${ip_parts[2]:-0}:*:*:*:*:*"
IPhide=$(echo "$IPhide"|sed 's/:0\{1,\}/:/g'|sed 's/::\+/:/g')
else
IPhide=""
fi
}
calculate_display_width(){
local string="$1"
local length=0
local char
for ((i=0; i<${#string}; i++));do
char=$(echo "$string"|od -An -N1 -tx1 -j $((i))|tr -d ' ')
if [ "$(printf '%d\n' 0x$char)" -gt 127 ];then
length=$((length+2))
i=$((i+1))
else
length=$((length+1))
fi
done
echo "$length"
}
calc_padding(){
local input_text="$1"
local total_width=$2
local title_length=$(calculate_display_width "$input_text")
local left_padding=$(((total_width-title_length)/2))
if [[ $left_padding -gt 0 ]];then
PADDING=$(printf '%*s' $left_padding)
else
PADDING=""
fi
}
parse_date(){
local input="$1"
local parsed_date=""
[[ -z $input ]]&&echo ""&&return
if [[ $input =~ ^[0-9]{4}-[0-9]{1,2}-[0-9]{1,2}$ ]];then
parsed_date="$(echo "$input"|awk -F'-' '{printf "%04d-%02d-%02d", $1, $2, $3}')"
elif [[ $input =~ ^[0-9]{8}$ ]];then
parsed_date="$(echo "$input"|sed -E 's/(.{4})(.{2})(.{2})/\1-\2-\3/')"
elif [[ $input =~ ^[0-9]{4}/[0-9]{1,2}/[0-9]{1,2}$ ]];then
parsed_date="$(echo "$input"|awk -F'/' '{printf "%04d-%02d-%02d", $1, $2, $3}')"
elif [[ $input =~ ^[0-9]{1,2}\ [A-Za-z]{3}\ [0-9]{4} ]];then
parsed_date="$(date -d "$input" +"%Y-%m-%d" 2>/dev/null)"
elif [[ $input =~ ^[0-9]{4}-[0-9]{1,2}-[0-9]{1,2}T[0-9]{2}:[0-9]{2}:[0-9]{2}Z$ ]];then
parsed_date="$(echo "$input"|awk -F'[T-]' '{printf "%04d-%02d-%02d", $1, $2, $3}')"
fi
echo "${parsed_date:-}"
}
wrap_text(){
local indent=$1
local text=$2
local max_len=$((80-indent))
local indent_spaces=$(printf '%*s' $indent)
local result=""
while [[ ${#text} -gt $max_len ]];do
local cut_pos=$(echo "${text:0:max_len}"|awk '{print length($0)-length($NF)}')
result+="${text:0:cut_pos}\n\r$indent_spaces"
text="${text:$((cut_pos))}"
done
result+="$text"
echo -e "$result"
}
generate_uuidv4(){
local uuid=""
local chars="0123456789abcdef"
for i in {1..36};do
if [[ $i == 9 || $i == 14 || $i == 19 || $i == 24 ]];then
uuid+="-"
elif [[ $i == 15 ]];then
uuid+="4"
elif [[ $i == 20 ]];then
r=$((RANDOM%16))
y=$((r&0x3|0x8))
uuid+=${chars:y:1}
else
r=$((RANDOM%16))
uuid+=${chars:r:1}
fi
done
echo "$uuid"
}
replace_html_entities(){
echo "$1"|sed -E \
-e 's/&#45;/-/g' \
-e 's/&#38;/\&/g' \
-e 's/&#39;/'\''/g' \
-e 's/&#34;/"/g' \
-e 's/&#60;/</g' \
-e 's/&#62;/>/g' \
-e 's/&#160;/ /g' \
-e 's/&amp;/\&/g'
}
calc_upstream(){
local RESPONSE=$2
local src_path=$(echo "$RESPONSE"|sed -n 's|.*src="\(/pathimg/[^"]*\)".*|\1|p')
local uuid=$(generate_uuidv4)
local extra_string="&loggedin"
local svg_content=$(curl $CurlARG -$1 --user-agent "$UA_Browser" --max-time 10 -Ls "https://bgp.tools$src_path?$uuid$extra_string")
local as_cards=()
local arrows=()
local inside_as_card=0
local inside_arrow=0
local current_block=""
while IFS= read -r line;do
if [[ $line =~ \<g\ id=\"[^\"]*\"\ class=\"node\" ]];then
inside_as_card=1
current_block="$line"
continue
fi
if [[ $line =~ \<g\ id=\"[^\"]*\"\ class=\"edge\" ]];then
inside_arrow=1
current_block="$line"
continue
fi
if [[ $inside_as_card -eq 1 ]];then
current_block+=$'\n'"$line"
if [[ $line == *"</g>"* ]];then
as_cards+=("$current_block")
inside_as_card=0
current_block=""
fi
fi
if [[ $inside_arrow -eq 1 ]];then
current_block+=$'\n'"$line"
if [[ $line == *"</g>"* ]];then
arrows+=("$current_block")
inside_arrow=0
current_block=""
fi
fi
done <<<"$svg_content"
local as_card
local target_as_number=""
for as_card in "${as_cards[@]}";do
local id=$(echo "$as_card"|awk -F 'id="node|"' '/<g id="node/{print $2}')
id=${id:-0}
casn[$id]=$(echo "$as_card"|awk -F '[<>]' '/<text.*font-weight="bold".*>/{print $3}'|sed 's/AS//')
casn[$id]="${casn[$id]:-0}"
if [[ ${casn[$id]} -eq 0 ]];then
corg[$id]="IX Route"
continue
else
corg[$id]=$(echo "$as_card"|awk -F '[<>]' '/<text.*font-size="10.00".*>/{print $3}')
corg[$id]=$(replace_html_entities "${corg[$id]}")
corg[$id]="${corg[$id]:-"unknown"}"
fi
if echo "$as_card"|grep -q 'stroke="limegreen"';then
target_as_number="${casn[$id]}"
ctarget[$id]=true
ctier1[$id]=false
elif echo "$as_card"|grep -q 'fill="none"';then
ctarget[$id]=false
ctier1[$id]=false
elif echo "$as_card"|grep -q 'fill="white"';then
ctarget[$id]=false
ctier1[$id]=true
fi
cupstream[$id]=false
for arrow in "${arrows[@]}";do
local arrow_title=$(echo "$arrow"|awk -F '[<>]' '/<title>/{print $3}')
arrow_title=$(replace_html_entities "$arrow_title")
if [[ $arrow_title =~ AS$target_as_number.*AS${casn[$id]} ]];then
for sub_arrow in "${arrows[@]}";do
local sub_arrow_title=$(echo "$sub_arrow"|awk -F '[<>]' '/<title>/{print $3}')
sub_arrow_title=$(replace_html_entities "$sub_arrow_title")
if [[ $sub_arrow_title =~ AS${casn[$id]}.*AS[0-9]+ ]];then
cupstream[$id]=true
break 2
fi
done
fi
done
done
}
calc_ix(){
local RESULT=$(curl $CurlARG -$1 --user-agent "$UA_Browser" --max-time 10 -Ls "https://bgp.tools/ixp-rs-route/${bgp[prefix]}")
local ROWS=$(echo "$RESULT"|sed -n '/<table id="upstreamTable"/,/<\/table>/p'|grep "<tr>"|wc -l)
conn[ix]=$((ROWS-1))
}
calc_peers(){
local RESULT="$1"
if [[ $RESULT == *"This network is transit-free."* ]];then
conn[upstreams]=-2
else
local ROWS=$(echo "$RESULT"|sed -n '/<table id="upstreamTable"/,/<\/table>/p'|grep "<tr>"|wc -l)
conn[upstreams]=$((ROWS-1))
fi
ROWS=$(echo "$RESULT"|sed -n '/<table id="peersTable"/,/<\/table>/p'|grep "<tr>"|wc -l)
conn[peers]=$((ROWS-1))
}
get_bgp(){
bgp[org]="${bgp[org]:-${getbgp[org-name]:-${getbgp[organization]:-${getbgp[orgname]:-${getbgp[owner]:-${getbgp[dscr]%%,*:-${getbgp[netname]:-${getbgp[ownerid]:-${getbgp[mnt-by]}}}}}}}}}"
[[ ${getbgp[source]} =~ ^(RIPE|APNIC|ARIN|LACNIC|AFRINIC)$ ]]&&bgp[rir]="${getbgp[source]}"
[[ -z ${bgp[rir]} && ${getbgp[mnt-by]} =~ ^(RIPE|APNIC|ARIN|LACNIC|AFRINIC)- ]]&&bgp[rir]="${BASH_REMATCH[1]}"
[[ -z ${bgp[rir]} && -n ${getbgp[ownerid]} ]]&&bgp[rir]="LACNIC"
[[ -z ${bgp[rir]} && -n ${getbgp[orgtechhandle]} ]]&&bgp[rir]="ARIN"
if [[ -n ${getbgp[country]} ]];then
[[ -z ${bgp[countrycode]} ]]&&bgp[countrycode]="${getbgp[country]}"
[[ -z ${bgp[country]} ]]&&bgp[country]=$(echo "$ISO3166"|jq --arg code "${bgp[countrycode]}" -r '.[] | select(.["alpha-2"] == $code) | .name // ""')
[[ -z ${bgp[region]} ]]&&bgp[region]=$(echo "$ISO3166"|jq --arg code "${bgp[countrycode]}" -r '.[] | select(.["alpha-2"] == $code) | .region // ""')
[[ -z ${bgp[subregion]} ]]&&bgp[subregion]=$(echo "$ISO3166"|jq --arg code "${bgp[countrycode]}" -r '.[] | select(.["alpha-2"] == $code) | ."sub-region" // ""')
[[ -z ${bgp[intermediateregion]} ]]&&bgp[intermediateregion]=$(echo "$ISO3166"|jq --arg code "${bgp[countrycode]}" -r '.[] | select(.["alpha-2"] == $code) | ."intermediate-region" // ""')
[[ ${bgp[region]} == "null" ]]&&bgp[region]=""
[[ ${bgp[subregion]} == "null" ]]&&bgp[subregion]=""
[[ ${bgp[intermediateregion]} == "null" ]]&&bgp[intermediateregion]=""
fi
[[ -z ${bgp[address]} && -n ${getbgp[address]} ]]&&bgp[address]="$(echo "${getbgp[address]}"|sed 's/,\+/,/g')"
[[ -z ${bgp[geofeed]} && -n ${getbgp[geofeed]} ]]&&bgp[geofeed]="${getbgp[geofeed]}"
[[ -z ${bgp[regdate]} ]]&&bgp[regdate]="$(parse_date "${getbgp[created]:-${getbgp[regdate]}}")"
[[ -z ${bgp[moddate]} ]]&&bgp[moddate]="$(parse_date "${getbgp[last-modified]:-${getbgp[updated]:-${getbgp[changed]}}}")"
}
db_bgptools(){
local temp_info="$Font_Cyan$Font_B${sinfo[bgp]}${Font_I}BGP.TOOLS $Font_Suffix"
((ibar_step+=1))
show_progress_bar "$temp_info" $((50-10-${sinfo[lbgp]}))&
bar_pid="$!"&&disown "$bar_pid"
trap "kill_progress_bar" RETURN
bgp=()
getbgp=()
conn=()
casn=()
corg=()
ctarget=()
ctier1=()
cupstream=()
local RESPONSE=$(curl $CurlARG -$1 --user-agent "$UA_Browser" --max-time 10 -Ls "https://bgp.tools/prefix/$IP")
if [[ $RESPONSE == *"Overlapping Prefixes Detected"* ]];then
bgp[prefix]=$(echo "$RESPONSE"|grep -o 'href="/prefix/[^"]*'|head -1|cut -d'/' -f3-)
RESPONSE=$(curl $CurlARG -$1 --user-agent "$UA_Browser" --max-time 10 -Ls "https://bgp.tools/prefix/${bgp[prefix]}")
fi
bgp[prefix]=$(echo "$RESPONSE"|sed -n 's/.*<p id="network-name" class="heading-xlarge">\([^<]*\)<\/p>.*/\1/p')
if [[ ${bgp[prefix]} == */* ]];then
bgp[ip0]="${bgp[prefix]%%/*}"
bgp[prefixnum]="${bgp[prefix]##*/}"
fi
bgp[asn]=$(echo "$RESPONSE"|awk -v RS='<strong>' '/Originated by/ {getline; print $0}'|sed 's/<[^>]*>//g'|head -n 1)
bgp[asn]="${bgp[asn]%%,*}"
bgp[org]=$(echo "$RESPONSE"|sed -n 's/.*AS Name: <strong>\([^<]*\)<\/strong>.*/\1/p')
local last_field_name=""
local CONTENT=$(echo "$RESPONSE"|sed -n '/<div style="display: none" id="whois-page">/,/<\/div>/p'|sed -n '/<pre style="white-space: pre-wrap;">/,/<\/pre>/p'|sed 's/<pre style="white-space: pre-wrap;">//'|sed 's/<[^>]*>//g')
while IFS= read -r line;do
[[ -z $line ]]&&continue
if [[ $line == *:* ]];then
if [[ $line =~ ^([^:]+):(.*)$ ]];then
field_name="${BASH_REMATCH[1],,}"
field_value=$(echo "${BASH_REMATCH[2]}"|sed -e 's/^[[:space:]]*//' -e 's/[[:space:]]*$//')
fi
[[ -z $field_value ]]&&continue
if [[ $field_name == "$last_field_name" ]];then
getbgp["$field_name"]+=", $field_value"
elif [[ -z ${getbgp[$field_name]} ]];then
getbgp["$field_name"]="$field_value"
last_field_name="$field_name"
else
last_field_name=""
fi
fi
done <<<"$CONTENT"
get_bgp
calc_upstream $1 "$RESPONSE"
calc_ix $1
calc_peers "$RESPONSE"
}
db_henet(){
local temp_info="$Font_Cyan$Font_B${sinfo[bgp]}${Font_I}HE.NET $Font_Suffix"
((ibar_step+=4))
show_progress_bar "$temp_info" $((50-7-${sinfo[lbgp]}))&
bar_pid="$!"&&disown "$bar_pid"
trap "kill_progress_bar" RETURN
getbgp=()
local last_field_name=""
local attempts=0
local max_attempts=5
local RESPONSE=""
local CONTENT=""
while [[ $attempts -lt $max_attempts ]];do
RESPONSE=$(curl $CurlARG -$1 --user-agent "$UA_Browser" --max-time 10 -Ls "https://bgp.he.net/whois/ip/$IP")
if echo "$RESPONSE"|jq empty 2>/dev/null;then
CONTENT=$(echo "$RESPONSE"|jq -r '.data' 2>/dev/null)
if [[ -n $CONTENT ]];then
break
fi
fi
((attempts++))
sleep 3
done
CONTENT=$(echo "$CONTENT"|sed 's/\\n/\n/g'|sed 's/\\t/\t/g')
while IFS= read -r line;do
[[ -z $line ]]&&continue
if [[ $line == *:* ]];then
if [[ $line =~ ^([^:]+):(.*)$ ]];then
field_name="${BASH_REMATCH[1],,}"
field_value=$(echo "${BASH_REMATCH[2]}"|sed -e 's/^[[:space:]]*//' -e 's/[[:space:]]*$//')
fi
[[ -z $field_value ]]&&continue
if [[ $field_name == "$last_field_name" ]];then
getbgp["$field_name"]+=", $field_value"
elif [[ -z ${getbgp[$field_name]} ]];then
getbgp["$field_name"]="$field_value"
last_field_name="$field_name"
else
last_field_name=""
fi
fi
done <<<"$CONTENT"
bgp[asn]="${bgp[asn]:-${getbgp[origin]:-${getbgp[originas]:-${getbgp[aut-num]}}}}"
[[ ${bgp[asn]} == "N/A" ]]&&bgp[asn]=""
bgp[prefix]="${bgp[prefix]:-${getbgp[route]:-${getbgp[route6]:-${getbgp[cidr]:-${getbgp[inetrev]}}}}}"
if [[ ${bgp[prefix]} == */* ]];then
bgp[ip0]="${bgp[prefix]%%/*}"
bgp[prefixnum]="${bgp[prefix]##*/}"
fi
get_bgp
}
get_neighbor(){
local temp_info="$Font_Cyan$Font_B${sinfo[neighbor]}$Font_Suffix"
((ibar_step+=1))
show_progress_bar "$temp_info" $((50-${sinfo[lneighbor]}))&
bar_pid="$!"&&disown "$bar_pid"
trap "kill_progress_bar" RETURN
local convert_output
local cidr="${IP%.*}.0/24"
if [[ ${bgp[prefixnum]} != "24" ]];then
bgp[neighbortotal]="256"
convert_output=$(curl -s -m 10 --user-agent "$UA_Browser" "https://bgp.tools/pfximg/$cidr"|convert png:- txt:- 2>/dev/null)
[[ -n $convert_output ]]&&bgp[neighboractive]=$(grep -E -c "#0003FF|#4041BE" <<<"$convert_output")
fi
bgp[iptotal]="$((2**(32-${bgp[prefixnum]})))"
convert_output=$(curl -s -m 10 --user-agent "$UA_Browser" "https://bgp.tools/pfximg/${bgp[prefix]}"|convert png:- txt:- 2>/dev/null)
[[ -n $convert_output ]]&&bgp[ipactive]=$(grep -E -c "#0003FF|#4041BE" <<<"$convert_output")
}
generate_uuidv4(){
local uuid=""
local chars="0123456789abcdef"
for i in {1..36};do
if [[ $i == 9 || $i == 14 || $i == 19 || $i == 24 ]];then
uuid+="-"
elif [[ $i == 15 ]];then
uuid+="4"
elif [[ $i == 20 ]];then
r=$((RANDOM%16))
y=$((r&0x3|0x8))
uuid+=${chars:y:1}
else
r=$((RANDOM%16))
uuid+=${chars:r:1}
fi
done
echo "$uuid"
}
get_nat(){
local temp_info="$Font_Cyan$Font_B${sinfo[nat]}$Font_Suffix"
((ibar_step+=1))
show_progress_bar "$temp_info" $((50-${sinfo[lnat]}))&
bar_pid="$!"&&disown "$bar_pid"
trap "kill_progress_bar" RETURN
getnat=()
if [[ $rawgithub == *"github.com"* ]];then
local result=$(stun "stun.l.google.com" 2>/dev/null)
else
local result=$(stun "stun.miwifi.com" 2>/dev/null)
fi
getnat[nat]=$(echo "$result"|grep -oE "0x[0-9A-Fa-f]+")
[[ -z ${getnat[nat]} ]]&&return 1
local val=$((${getnat[nat]}))
local portpres=$((val&0x01))
local filtering=$(((val&0x06)>>1))
local mapping=$(((val&0x08)>>3))
local hairpin=$(((val&0x10)>>4))
getnat[m]=$mapping
getnat[f]=$filtering
getnat[p]=$portpres
getnat[h]=$hairpin
local ntype="fail"
getnat[char]=0
if [[ ${getnat[nat]} == "0xFFFFFFFF" || ${getnat[nat]} == "0x0000EE" ]];then
ntype="fail"
elif [[ $mapping -eq 1 && $filtering -eq 1 ]];then
ntype="firewall"
elif [[ $mapping -eq 1 && $filtering -eq 2 ]];then
ntype="block"
elif [[ $mapping -eq 1 && $filtering -eq 3 ]];then
ntype="unknown"
elif [[ $mapping -eq 0 && $filtering -eq 0 ]];then
ntype="open"
elif [[ $mapping -eq 0 && $filtering -eq 1 ]];then
ntype="full"
[[ $hairpin -eq 0 ]]&&slocal[full]="$Back_Green${slocal[full]}"||slocal[full]="$Back_Yellow${slocal[full]}"
getnat[char]=1
elif [[ $mapping -eq 0 && $filtering -eq 2 ]];then
ntype="rest"
getnat[char]=1
elif [[ $mapping -eq 0 && $filtering -eq 3 ]];then
ntype="portrest"
getnat[char]=1
elif [[ $mapping -eq 1 ]];then
ntype="symm"
getnat[char]=1
fi
getnat[type]=$ntype
}
get_tcp(){
local temp_info="$Font_Cyan$Font_B${sinfo[tcp]}$Font_Suffix"
((ibar_step+=1))
show_progress_bar "$temp_info" $((50-${sinfo[ltcp]}))&
bar_pid="$!"&&disown "$bar_pid"
trap "kill_progress_bar" RETURN
gettcp=()
gettcp[tcpcc]=$(sysctl -n net.ipv4.tcp_congestion_control 2>/dev/null|awk '{$1=$1};1'||echo "N/A")
gettcp[qdisc]=$(sysctl -n net.core.default_qdisc 2>/dev/null|awk '{$1=$1};1'||echo "N/A")
gettcp[rmem]=$(sysctl -n net.ipv4.tcp_rmem 2>/dev/null|awk '{$1=$1};1'||echo "N/A")
gettcp[wmem]=$(sysctl -n net.ipv4.tcp_wmem 2>/dev/null|awk '{$1=$1};1'||echo "N/A")
}
calculate_delay(){
local delay=0x2800
local num1=$1
local num2=$2
if [[ $(echo "$num1 > 0 && $num1 <= 80"|bc) -eq 1 ]];then
delay=$((delay+0x40))
elif [[ $(echo "$num1 > 80 && $num1 <= 160"|bc) -eq 1 ]];then
delay=$((delay+0x44))
elif [[ $(echo "$num1 > 160 && $num1 <= 240"|bc) -eq 1 ]];then
delay=$((delay+0x46))
elif [[ $(echo "$num1 > 200"|bc) -eq 1 ]];then
delay=$((delay+0x47))
fi
if [[ $(echo "$num2 > 0 && $num2 <= 80"|bc) -eq 1 ]];then
delay=$((delay+0x80))
elif [[ $(echo "$num2 > 80 && $num2 <= 160"|bc) -eq 1 ]];then
delay=$((delay+0xA0))
elif [[ $(echo "$num2 > 160 && $num2 <= 240"|bc) -eq 1 ]];then
delay=$((delay+0xB0))
elif [[ $(echo "$num2 > 240"|bc) -eq 1 ]];then
delay=$((delay+0xB8))
fi
local delay_hex=$(printf "%X" "$delay")
local unicode_char=$(echo -e "\u${delay_hex: -4}")
if [[ $(echo "$num1 > 240"|bc) -eq 1 || $(echo "$num2 > 240"|bc) -eq 1 || $(echo "$num1 == 0"|bc) -eq 1 || $(echo "$num2 == 0"|bc) -eq 1 ]];then
echo "$Font_Red$unicode_char"
elif [[ $(echo "$num1 > 150"|bc) -eq 1 || $(echo "$num2 > 150"|bc) -eq 1 ]];then
echo "$Font_Yellow$unicode_char"
elif [[ $(echo "$num1 <= 150"|bc) -eq 1 && $(echo "$num2 <= 150"|bc) -eq 1 ]];then
echo "$Font_Green$unicode_char"
else
echo "$Font_Red$unicode_char"
fi
}
ping_test(){
local domain=$1
local protocol=$2
local psize=$3
local count=$4
local pv=$5
local provider=$6
local ipv=$7
local port=$8
[[ -z $domain || -z $ipv || -z $protocol || -z $psize || -z $count || -z $pv || -z $provider ]]&&return 1
[[ $ipv != "4" && $ipv != "6" ]]&&return 1
[[ $protocol != "ICMP" && $protocol != "TCP" && $protocol != "UDP" ]]&&return 1
[[ -z $port ]]&&port=80
local response
local tmpresu=""
local pingcom=""
if [[ $protocol == "ICMP" ]];then
pingcom="mtr -$ipv -c 1 -f 100 -C -G 1 -s $psize $domain"
elif [[ $protocol == "TCP" ]];then
pingcom="mtr -$ipv --tcp -P $port -c 1 -f 100 -C -G 1 -s $psize $domain"
elif [[ $protocol == "UDP" ]];then
pingcom="mtr -$ipv --udp -P $port -c 1 -f 100 -C -G 1 -s $psize $domain"
fi
response=$($pingcom 2>&1)
tmpresu=$(echo "$response"|tr -d '\n'|awk -F',' '{print $24}')
[[ -z $tmpresu || ! $tmpresu =~ ^[0-9]+(\.[0-9]+)?$ || ${#tmpresu} -gt 6 ]]&&tmpresu=0.00
echo "$pv $provider $ipv $count $tmpresu"
}
process_pingtestresult(){
local testresult=$1
local -A midresu
local tmp_space=""
local ipv
local index
local numbers
local total
local count
local lost
local result
[[ $mode_ping -eq 1 ]]&&tmp_space=" "
IFS=$'\n' read -r -d '' -a lines <<<"$testresult"
for line in "${lines[@]}";do
line=$(echo "$line"|xargs)
[[ -z $line ]]&&continue
IFS=' ' read -ra parts <<<"$line"
index="${parts[0]}${parts[1]}${parts[2]}${parts[3]}"
ipv="${parts[2]}"
pout[$index]="${parts[4]}"
done
for province in $(echo "${!pcode[@]}"|sort -n);do
for j in 1 2 3;do
total=0
count=0
lost=""
for i in $(seq 1 $ping_test_count);do
numbers=${pout[$province$j$ipv$i]}
if [[ $numbers =~ ^0\.0*$ ]];then
lost="$Font_Red"
else
total=$(echo "$total + $numbers"|bc)
((count++))
fi
done
if ((count>0));then
local avg=$(echo "scale=0; $total / $count"|bc)
else
local avg=0
fi
result=""
for ((i=1; i<ping_test_count; i+=2));do
local A="${pout[$province$j$ipv$i]}"
local B="${pout[$province$j$ipv$((i+1))]}"
local char=$(calculate_delay "$A" "$B")
result+="$char"
done
if [[ $avg -gt 240 || $lost == "$Font_Red" ]];then
lost="$Font_Red"
elif [[ $avg -gt 150 ]];then
lost="$Font_Yellow"
elif [[ $avg -le 150 ]];then
lost="$Font_Green"
else
lost="$Font_Red"
fi
pavg[$province$j$ipv]="$avg"
midresu[$province$j$ipv]="$Font_Green$result$lost$Font_B$(printf '%-3s' "$avg")$Font_Suffix"
done
local prov_space=""
[[ $mode_ping -eq 1 ]]&&prov_space=" "
if [[ $YY == "cn" ]];then
presu[$province]="$Font_Cyan${pshort[$province]}$prov_space${midresu[${province}1$ipv]}$tmp_space${midresu[${province}2$ipv]}$tmp_space${midresu[${province}3$ipv]}"
else
presu[$province]="$Font_Cyan${pcode[$province]}$prov_space${midresu[${province}1$ipv]}$tmp_space${midresu[${province}2$ipv]}$tmp_space${midresu[${province}3$ipv]}"
fi
done
}
get_delay(){
local temp_info="$Font_Cyan$Font_B${sinfo[delay]}$Font_Suffix"
((ibar_step+=1))
show_progress_bar "$temp_info" $((50-${sinfo[ldelay]}))&
bar_pid="$!"&&disown "$bar_pid"
trap "kill_progress_bar" RETURN
[[ $mode_ping -eq 1 ]]&&ping_test_count=44
local max_threads=93
local available_memory=1024
[[ "$(uname)" != "Darwin" ]]&&available_memory=$(free -m|awk '/Mem:/ {print $7}')
local max_threads_by_memory=$(echo "$available_memory / 8"|bc)
((max_threads_by_memory<max_threads))&&max_threads=$max_threads_by_memory
local current_threads=0
local tmpresult=$(for i in $(seq 1 $ping_test_count)
do
for province in $(echo "${!pcode[@]}"|sort -n);do
for j in 1 2 3;do
ping_test "${pdm[$province$j$1]}" "TCP" 1400 "$i" "$province" "$j" "$1"&
((current_threads++))
if ((current_threads>=max_threads));then
wait -n
((current_threads--))
fi
done
done
done
wait)
process_pingtestresult "$tmpresult"
}
show_delay(){
local count=0
local resu_per_line=$(((display_max_len+1)/(ping_test_count*3/2+12)))
if [[ $mode_ping -eq 1 ]];then
resu_per_line=1
echo -ne "\r${sdelay[pingmode]}\n"
else
count=2
echo -ne "\r${sdelay[title]}"
fi
for key in $(echo "${!pcode[@]}"|tr ' ' '\n'|sort -n);do
((count++))
if ((resu_per_line==1));then
echo -ne "\r${presu[$key]}\n"
elif ((count%resu_per_line==0));then
echo -ne "${presu[$key]}\n"
elif ((count%resu_per_line==1));then
echo -ne "\r${presu[$key]} "
else
echo -ne "${presu[$key]} "
fi
done
((count%resu_per_line!=0))&&echo
}
nexttrace_test(){
local domain="$1"
local rmode="$2"
local rnum="$3"
local ipv="$4"
local response
local max_retries=10
local retry_delay=5
local retry_count=0
while [[ $retry_count -lt $max_retries ]];do
response=$(timeout -s SIGKILL 50 nexttrace -p 80 -q 8 -"$ipv" --"$rmode" --raw --psize 1400 "$domain" 2>/dev/null)
[[ $response != *"*please try again later*"* && $response == *"traceroute to"* ]]&&break
retry_count=$((retry_count+1))
[[ $retry_count -lt $max_retries ]]&&sleep "$retry_delay"
done
declare -A ips asns regions orgs
local max_hop=0
local cn_hop=0
local all_asn=""
local tresucn=""
local tresuww="NoData"
while IFS= read -r line;do
if [[ $line != *"|"* ]];then
continue
fi
IFS='|' read -r -a elements <<<"$line"
local hop="${elements[0]}"
local ip="${elements[1]}"
local asn="${elements[4]}"
local region="${elements[5]}"
[[ ${elements[6]} == "香港" || ${elements[6]} == "澳门" || ${elements[6]} == "台湾" ]]&&region="${elements[6]}"
local org="${elements[9]}"
[[ -n ${ips[$hop]} ]]&&continue
[[ $ip == 59.43.* ]]&&asn="4809"
[[ $org == *CTGNet* ]]&&asn="23764"
[[ $cn_hop == 0 && $region == *中国* ]]&&cn_hop=$hop
[[ -n $asn ]]&&all_asn="${all_asn}AS$asn "
ips["$hop"]="$ip"
asns["$hop"]="$asn"
regions["$hop"]="$region"
orgs["$hop"]="$org"
if ((hop>max_hop));then
max_hop="$hop"
fi
done <<<"$response"
[[ $cn_hop == 0 || $cn_hop == $max_hop ]]&&tresucn="Hidden"
[[ ${asns[$cn_hop]} == "17676" ]]&&cn_hop=$((cn_hop+1))
case "${asns[$cn_hop]}" in
"4134")tresucn="163"
;;
"4837")tresucn="4837"
if ((cn_hop>1));then
[[ ${asns[$((cn_hop-1))]} == "10099" ]]&&tresucn="10099"
fi
;;
"58453")tresucn="CMI"
;;
"58807")tresucn="CMIN2"
;;
"9808")tresucn="CMI"
[[ $all_asn == *AS58807* ]]&&tresucn="CMIN2"
;;
"9929")tresucn="9929"
;;
"10099")tresucn="10099"
[[ $all_asn == *AS9929* ]]&&tresucn="9929"
;;
"4809")tresucn="CN2GIA"
if ((cn_hop>1));then
[[ $all_asn == *AS23764* ]]&&tresucn="CTGGIA"
else
for ((hop=cn_hop; hop<=max_hop; hop++));do
[[ ${asns[$hop]} == "4809" || ${asns[$hop]} == "23764" ]]&&continue
if [[ ${ips[$hop]} == 202.97* ]];then
tresucn="CN2GT"
fi
break
done
fi
;;
"23764")tresucn="CTGGIA"
;;
"4538")tresucn="CERNET"
;;
"7497")tresucn="CSTNET"
;;
*)tresucn="NoData"
if [[ $all_asn == *AS58807* ]];then
tresucn="CMIN2"
elif [[ $all_asn == *AS9929* ]];then
tresucn="9929"
elif [[ $all_asn == *AS10099* ]];then
tresucn="10099"
elif [[ $all_asn == *AS4809* ]];then
tresucn="CN2"
elif [[ $all_asn == *AS9808* ]];then
tresucn="CMI"
elif [[ $all_asn == *AS4134* ]];then
tresucn="163"
elif [[ $all_asn == *AS4837* ]];then
tresucn="4837"
fi
esac
for ((hop=cn_hop-1; hop>0; hop--));do
if [[ -n ${asns[$hop]} && ${asns[$hop]} != "58453" && ${asns[$hop]} != "58807" && ${asns[$hop]} != "4837" && ${asns[$hop]} != "10099" && ${asns[$hop]} != "9929" && ${asns[$hop]} != "4134" && ${asns[$hop]} != "4809" && ${asns[$hop]} != "4808" && ${asns[$hop]} != "23764" && ${asns[$hop]} != "4538" && ${asns[$hop]} != "7497" ]];then
tresuww="AS${asns[$hop]}"
break
fi
done
if [[ -n $tresuww ]];then
[[ -n ${AS_MAPPING[$tresuww]} ]]&&tresuww="${AS_MAPPING[$tresuww]}"
fi
echo "$rnum $tresuww $tresucn"
}
mtr_test(){
local domain="$1"
local rmode="$2"
local rnum="$3"
local ipv="$4"
declare -A ips
declare -A asns
local max_hop=0
local cn_hop=0
local all_asn=""
local tresucn="NoData"
local tresuww="NoData"
local max_retries=10
local retry_delay=5
local retry_count=0
while [[ $retry_count -lt $max_retries ]];do
response=$(timeout 60 mtr -"$ipv" --"$rmode" --no-dns -y 0 -P 80 -c 8 -C -Z 1 -G 1 -s 1400 "$domain" 2>/dev/null)
[[ $response != *"*mtr:*"* && $response == *"OK,"* ]]&&break
retry_count=$((retry_count+1))
[[ $retry_count -lt $max_retries ]]&&sleep "$retry_delay"
done
while IFS= read -r line;do
[[ $line != *"OK,"* ]]&&continue
IFS=',' read -r -a elements <<<"$line"
local hop="${elements[4]}"
local ip="${elements[5]}"
[[ ${elements[6]} != *"?"* ]]&&local asn="${elements[6]#AS}"
ips["$hop"]="$ip"
asns["$hop"]="$asn"
[[ -n $asn && $asn != *"?"* ]]&&all_asn="$all_asn$asn "
((hop>max_hop))&&max_hop="$hop"
[[ $cn_hop -eq 0 ]]&&[[ $asn =~ ^("58453"|"58807"|"4837"|"10099"|"9929"|"4134"|"4809"|"23764"|"4538"|"7497")$ ]]&&cn_hop="$hop"
done <<<"$response"
[[ $cn_hop == 0 || $cn_hop == $max_hop ]]&&tresucn="Hidden"
[[ ${asns[$cn_hop]} == "17676" ]]&&cn_hop=$((cn_hop+1))
case "${asns[$cn_hop]}" in
"4134")tresucn="163"
if [[ $all_asn == *AS9929* ]];then
tresucn="9929"
elif [[ $all_asn == *AS10099* ]];then
tresucn="10099"
elif [[ $all_asn == *AS23764* && $all_asn == *AS4134* ]];then
tresucn="CN2GT"
elif [[ $all_asn == *AS4809* && $all_asn == *AS4134* ]];then
tresucn="CN2GT"
elif [[ $all_asn == *AS23764* ]];then
tresucn="CTGGIA"
elif [[ $all_asn == *AS4809* ]];then
tresucn="CN2GIA"
elif [[ $all_asn == *AS58807* ]];then
tresucn="CMIN2"
fi
;;
"4837")tresucn="4837"
if [[ $all_asn == *AS9929* ]];then
tresucn="9929"
elif [[ $all_asn == *AS10099* ]];then
tresucn="10099"
elif [[ $all_asn == *AS23764* && $all_asn == *AS4134* ]];then
tresucn="CN2GT"
elif [[ $all_asn == *AS4809* && $all_asn == *AS4134* ]];then
tresucn="CN2GT"
elif [[ $all_asn == *AS23764* ]];then
tresucn="CTGGIA"
elif [[ $all_asn == *AS4809* ]];then
tresucn="CN2GIA"
elif [[ $all_asn == *AS58807* ]];then
tresucn="CMIN2"
fi
;;
"58453")tresucn="CMI"
if [[ $all_asn == *AS9929* ]];then
tresucn="9929"
elif [[ $all_asn == *AS10099* ]];then
tresucn="10099"
elif [[ $all_asn == *AS23764* && $all_asn == *AS4134* ]];then
tresucn="CN2GT"
elif [[ $all_asn == *AS4809* && $all_asn == *AS4134* ]];then
tresucn="CN2GT"
elif [[ $all_asn == *AS23764* ]];then
tresucn="CTGGIA"
elif [[ $all_asn == *AS4809* ]];then
tresucn="CN2GIA"
elif [[ $all_asn == *AS58807* ]];then
tresucn="CMIN2"
fi
;;
"58807")tresucn="CMIN2"
;;
"9808")tresucn="CMI"
if [[ $all_asn == *AS9929* ]];then
tresucn="9929"
elif [[ $all_asn == *AS10099* ]];then
tresucn="10099"
elif [[ $all_asn == *AS23764* && $all_asn == *AS4134* ]];then
tresucn="CN2GT"
elif [[ $all_asn == *AS4809* && $all_asn == *AS4134* ]];then
tresucn="CN2GT"
elif [[ $all_asn == *AS23764* ]];then
tresucn="CTGGIA"
elif [[ $all_asn == *AS4809* ]];then
tresucn="CN2GIA"
elif [[ $all_asn == *AS58807* ]];then
tresucn="CMIN2"
fi
;;
"9929")tresucn="9929"
;;
"10099")tresucn="10099"
[[ $all_asn == *AS9929* ]]&&tresucn="9929"
;;
"4809")tresucn="CN2GIA"
if ((cn_hop>1));then
[[ $all_asn == *AS23764* ]]&&tresucn="CTGGIA"
else
for ((hop=cn_hop; hop<=max_hop; hop++));do
[[ ${asns[$hop]} == "4809" || ${asns[$hop]} == "23764" ]]&&continue
if [[ ${ips[$hop]} == 202.97* ]];then
tresucn="CN2GT"
fi
break
done
fi
;;
"23764")tresucn="CTGGIA"
;;
"4538")tresucn="CERNET"
;;
"7497")tresucn="CSTNET"
;;
*)tresucn="NoData"
if [[ $all_asn == *AS58807* ]];then
tresucn="CMIN2"
elif [[ $all_asn == *AS9929* ]];then
tresucn="9929"
elif [[ $all_asn == *AS10099* ]];then
tresucn="10099"
elif [[ $all_asn == *AS4809* ]];then
tresucn="CN2"
elif [[ $all_asn == *AS9808* ]];then
tresucn="CMI"
elif [[ $all_asn == *AS4134* ]];then
tresucn="163"
elif [[ $all_asn == *AS4837* ]];then
tresucn="4837"
fi
esac
for ((hop=cn_hop-1; hop>0; hop--));do
if [[ -n ${asns[$hop]} && ${asns[$hop]} != "58453" && ${asns[$hop]} != "58807" && ${asns[$hop]} != "4837" && ${asns[$hop]} != "10099" && ${asns[$hop]} != "9929" && ${asns[$hop]} != "4134" && ${asns[$hop]} != "4809" && ${asns[$hop]} != "23764" && ${asns[$hop]} != "4538" && ${asns[$hop]} != "7497" ]];then
tresuww="AS${asns[$hop]}"
break
fi
done
if [[ -n $tresuww ]];then
[[ -n ${AS_MAPPING[$tresuww]} ]]&&tresuww="${AS_MAPPING[$tresuww]}"
fi
echo "$rnum $tresuww $tresucn"
}
get_route(){
ibar_step=19
local temp_info="$Font_Cyan$Font_B${sinfo[route]}$Font_Suffix"
((ibar_step+=1))
show_progress_bar "$temp_info" $((50-${sinfo[lroute]}))&
bar_pid="$!"&&disown "$bar_pid"
trap "kill_progress_bar" RETURN
local ipv=$1
local rdomain
rdomain[1]="bj-ct-v$ipv.ip.zstaticcdn.com"
rdomain[2]="bj-cu-v$ipv.ip.zstaticcdn.com"
rdomain[3]="bj-cm-v$ipv.ip.zstaticcdn.com"
rdomain[4]="sh-ct-v$ipv.ip.zstaticcdn.com"
rdomain[5]="sh-cu-v$ipv.ip.zstaticcdn.com"
rdomain[6]="sh-cm-v$ipv.ip.zstaticcdn.com"
rdomain[7]="gd-ct-v$ipv.ip.zstaticcdn.com"
rdomain[8]="gd-cu-v$ipv.ip.zstaticcdn.com"
rdomain[9]="gd-cm-v$ipv.ip.zstaticcdn.com"
local max_threads=18
local available_memory=1024
[[ "$(uname)" != "Darwin" ]]&&available_memory=$(free -m|awk '/Mem:/ {print $7}')
local max_threads_by_memory=$(echo "$available_memory / 28"|bc)
((max_threads_by_memory<max_threads))&&max_threads=$max_threads_by_memory
local current_threads=0
local tmpresult=$(for i in $(seq 1 18)
do
local protocol="tcp"
((i%2==0))&&protocol="udp"
if [[ $protocol == "udp" && $ipv == "6" ]];then
mtr_test "${rdomain[$(((i+1)/2))]}" "$protocol" "$i" "$ipv"&
else
nexttrace_test "${rdomain[$(((i+1)/2))]}" "$protocol" "$i" "$ipv"&
fi
((current_threads++))
if ((current_threads>=max_threads));then
wait -n
((current_threads--))
else
sleep 2
fi
done
wait)
while IFS= read -r line;do
[[ -z $line ]]&&continue
read -r index rww_value rcn_value <<<"$line"
[[ $rcn_value == *GIA ]]&&rgia=1
done <<<"$tmpresult"
while IFS= read -r line;do
[[ -z $line ]]&&continue
read -r index rww_value rcn_value <<<"$line"
rww["$index"]="$rww_value"
rcn["$index"]="$rcn_value"
[[ ${rcn["$index"]} == "CN2GT" && $rgia -eq 1 ]]&&rcn["$index"]="CN2GIA"
printf -v spaceww "%$((8-${#rww_value}))s" ""
printf -v spacecn "%$((6-${#rcn_value}))s" ""
case "$rww_value" in
"Hidden")colorww="$Back_Red$Font_White$Font_U$Font_B";;
"NoData")colorww="$Back_Yellow$Font_White$Font_U$Font_B";;
*)colorww="$Back_Blue$Font_White$Font_U$Font_B"
esac
case "$rcn_value" in
"Hidden")colorcn="$Back_Red$Font_White$Font_U$Font_B";;
"NoData")colorcn="$Back_Yellow$Font_White$Font_U$Font_B";;
*)colorcn="$Back_Green$Font_White$Font_U$Font_B"
esac
routww["$index"]="$spaceww$colorww$rww_value$Font_Suffix"
routcn["$index"]="$colorcn$rcn_value$Font_Suffix$spacecn"
done <<<"$tmpresult"
}
function colorize_latency(){
local latency_ms=$1
local total_length=${2:-2}
local value
local pure_text
local padding
local colored_result
if [[ ! $latency_ms =~ ^[0-9]+(\.[0-9]+)?ms$ ]];then
echo ""
return 1
fi
value=$(echo "$latency_ms"|sed 's/ms//')
if (($(echo "$value <= 150"|bc -l)));then
colored_result="$Font_Green$latency_ms"
elif (($(echo "$value <= 240"|bc -l)));then
colored_result="$Font_Yellow$latency_ms"
else
colored_result="$Font_Red$latency_ms"
fi
pure_text="$latency_ms"
pure_length=${#pure_text}
if ((pure_length<total_length));then
padding=$((total_length-pure_length))
colored_result="$(printf "%${padding}s" "")$colored_result"
fi
colored_result="$colored_result$Font_Suffix"
echo -n "$colored_result"
return 0
}
show_route(){
echo -ne "\r${sroute[title]}\n"
if [[ $mode_route -eq 0 ]];then
echo -ne "\r$Font_Cyan北京TCP：$Font_Green电信 $Font_Suffix${routww[1]}$Font_Green->$Font_Suffix${routcn[1]} || $Font_Green联通$Font_Suffix $Font_Suffix${routww[3]}$Font_Green->$Font_Suffix${routcn[3]} || $Font_Green移动$Font_Suffix $Font_Suffix${routww[5]}$Font_Green->$Font_Suffix${routcn[5]}\n"
echo -ne "\r$Font_Cyan北京UDP：$Font_Green电信 $Font_Suffix${routww[2]}$Font_Green->$Font_Suffix${routcn[2]} || $Font_Green联通$Font_Suffix $Font_Suffix${routww[4]}$Font_Green->$Font_Suffix${routcn[4]} || $Font_Green移动$Font_Suffix $Font_Suffix${routww[6]}$Font_Green->$Font_Suffix${routcn[6]}\n"
echo -ne "\r$Font_Cyan上海TCP：$Font_Green电信 $Font_Suffix${routww[7]}$Font_Green->$Font_Suffix${routcn[7]} || $Font_Green联通$Font_Suffix $Font_Suffix${routww[9]}$Font_Green->$Font_Suffix${routcn[9]} || $Font_Green移动$Font_Suffix $Font_Suffix${routww[11]}$Font_Green->$Font_Suffix${routcn[11]}\n"
echo -ne "\r$Font_Cyan上海UDP：$Font_Green电信 $Font_Suffix${routww[8]}$Font_Green->$Font_Suffix${routcn[8]} || $Font_Green联通$Font_Suffix $Font_Suffix${routww[10]}$Font_Green->$Font_Suffix${routcn[10]} || $Font_Green移动$Font_Suffix $Font_Suffix${routww[12]}$Font_Green->$Font_Suffix${routcn[12]}\n"
echo -ne "\r$Font_Cyan广州TCP：$Font_Green电信 $Font_Suffix${routww[13]}$Font_Green->$Font_Suffix${routcn[13]} || $Font_Green联通$Font_Suffix $Font_Suffix${routww[15]}$Font_Green->$Font_Suffix${routcn[15]} || $Font_Green移动$Font_Suffix $Font_Suffix${routww[17]}$Font_Green->$Font_Suffix${routcn[17]}\n"
echo -ne "\r$Font_Cyan广州UDP：$Font_Green电信 $Font_Suffix${routww[14]}$Font_Green->$Font_Suffix${routcn[14]} || $Font_Green联通$Font_Suffix $Font_Suffix${routww[16]}$Font_Green->$Font_Suffix${routcn[16]} || $Font_Green移动$Font_Suffix $Font_Suffix${routww[18]}$Font_Green->$Font_Suffix${routcn[18]}\n"
else
local tmppv=""
local tmpfont=""
local tmpback=""
local tmpdelay=""
for ((i=1; i<=rmtestnum; i++));do
ii=$(printf "%02d" "$i")
case $((i%3)) in
1)tmppv="电信"
tmpfont="$Font_Cyan"
tmpback="$Back_Cyan"
;;
2)tmppv="联通"
tmpfont="$Font_Green"
tmpback="$Back_Green"
;;
0)tmppv="移动"
tmpfont="$Font_Purple"
tmpback="$Back_Purple"
esac
echo -ne "\r$tmpback$Font_White$Font_B  ${pname[${rmcode[$i]}]} $tmppv  $Font_Suffix$Back_White$tmpfont$Font_B  ${rmww[$ii]} -> ${rmcn[$ii]}  $Font_Suffix\n"
echo -ne "\r$Back_Blue$Font_White地理路径：${rmallgeo[$ii]}    自治系统路径：${rmallasn[$ii]} $Font_Suffix\n"
local varb="${rmmaxhop[$ii]:-0}"
varb=${varb#0}
local mergejump="   "
for ((j=1; j<=varb; j++));do
jj=$(printf "%02d" "$j")
mergeroute=0
mergejump="   "
if [[ -n ${rmresu[$ii${jj}2]} ]];then
local compA="${rmresu[$ii${jj}5]#"${rmresu[$ii${jj}5]%%[![:space:]\*]*}"}"
compA=$(awk '{print $1 " " $2}' <<<"$compA")
for ((k=j+1; k<varb; k++));do
kk=$(printf "%02d" "$k")
local compB="${rmresu[$ii${kk}5]#"${rmresu[$ii${kk}5]%%[![:space:]\*]*}"}"
compB=$(awk '{print $1 " " $2}' <<<"$compB")
if [[ -n ${rmresu[$ii${kk}2]} &&
${rmresu[$ii${jj}3]} == "${rmresu[$ii${kk}3]}" &&
${rmresu[$ii${jj}4]} == "${rmresu[$ii${kk}4]}" ]]&&[[ $compA == *"$compB"* ||
$compB == *"$compA"* ]];then
mergejump="-$(printf '%-2s' "$k")"
continue
fi
[[ -n ${rmresu[$ii${kk}2]} ]]&&break
done
if ((j!=varb));then
for ((k=j-1; k>0; k--));do
kk=$(printf "%02d" "$k")
local compB="${rmresu[$ii${kk}5]#"${rmresu[$ii${kk}5]%%[![:space:]\*]*}"}"
compB=$(awk '{print $1 " " $2}' <<<"$compB")
if [[ -n ${rmresu[$ii${kk}2]} &&
${rmresu[$ii${jj}3]} == "${rmresu[$ii${kk}3]}" &&
${rmresu[$ii${jj}4]} == "${rmresu[$ii${kk}4]}" ]]&&[[ $compA == *"$compB"* ||
$compB == *"$compA"* ]];then
continue 2
fi
done
fi
tmpdelay=$(colorize_latency "${rmresu[$ii${jj}1]}" 9)
if [[ $1 -eq 4 ]];then
echo -ne "\r$Font_B$(printf '%2s' "$j")$mergejump$Font_Suffix $tmpdelay  $(printf '%-13s' "${rmresu[$ii${jj}2]}")$Font_B$(printf '%-10s' "${rmresu[$ii${jj}3]}")$(printf '%-18s' "${rmresu[$ii${jj}4]}")$Font_Suffix${rmresu[$ii${jj}5]}\n"
else
echo -ne "\r$Font_B$(printf '%2s' "$j")$mergejump$Font_Suffix $tmpdelay  $(printf '%-27s' "${rmresu[$ii${jj}2]}")$Font_B$(printf '%-10s' "${rmresu[$ii${jj}3]}")$Font_Suffix${rmresu[$ii${jj}5]}\n"
fi
fi
done
done
fi
}
function mask_ip(){
local ip=$1
if [[ $ip =~ ^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$ ]];then
echo "$ip"|awk -F. '{print $1"."$2".*.*"}'
elif [[ $ip =~ ^([0-9a-fA-F]{0,4}:){2,7}[0-9a-fA-F]{0,4}$ ]];then
echo "$ip"|awk -F: '{
            # 计算需要保留的段数(总段数8减去要掩码的5段)
            keep = 8 - 5;
            for(i=1; i<=NF; i++) {
                if(i <= keep) {
                    printf "%s", $i;
                } else {
                    printf "*";
                }
                if(i < 8) printf ":";
            }
            # 处理压缩形式的IPv6(::)
            if(NF < 8) {
                for(i=NF+1; i<=8; i++) {
                    if(i <= keep) {
                        printf "0";
                    } else {
                        printf "*";
                    }
                    if(i < 8) printf ":";
                }
            }
        }'
else
return 1
fi
}
function extract_region(){
local input=$1
IFS=' ' read -ra parts <<<"$input"
local discard_patterns=("*" "中国" "电信" "联通" "移动")
local suffixes=("省" "市" "县" "维吾尔自治区" "回族自治区" "壮族自治区" "自治区" "特别行政区")
for part in "${parts[@]}";do
if [[ -z $part || $part =~ ^[[:punct:]]+$ || $part == *"."* || $part == *"RFC"* || $part == *"rfc"* || $part == *"Private"* || $part == *"Local"* || $part == *"DOD"* || $part == *"Anycast"* || $part == *"ASAPI"* || $part == *"网络故障"* ]];then
continue
fi
for pattern in "${discard_patterns[@]}";do
[[ $part == "$pattern" ]]&&continue 2
done
for suffix in "${suffixes[@]}";do
if [[ $part == *"$suffix" ]];then
part="${part%"$suffix"}"
break
fi
done
echo "$part"
return
done
echo ""
}
nexttrace_route(){
local domain="$1"
local rmode="$2"
local rnum="$3"
local ipv="$4"
local tmode
case "$rmode" in
1)tmode="--tcp";;
2)tmode="--udp"
esac
local output
local max_retries=10
local retry_delay=5
local retry_count=0
while [[ $retry_count -lt $max_retries ]];do
output=$(timeout -s SIGKILL 50 nexttrace -p 80 -q 8 -"$ipv" "$tmode" --psize 1400 "$domain" 2>/dev/null)
[[ $output != *"*please try again later*"* && $output == *"traceroute to"* ]]&&break
retry_count=$((retry_count+1))
[[ $retry_count -lt $max_retries ]]&&sleep "$retry_delay"
done
output=$(echo "$output"|sed 's/\x1b\[[0-9;]*m//g')
echo "$output"|awk -v rnum="$rnum" '
    {
        if ($1 ~ /^[0-9]+$/) {
            hop = $1
            ip = $2
            if (ip != "*") {
                as = ""
                bracket = ""
                desc = ""
                ms = ""
                # Extract AS information
                for (i = 3; i <= NF; i++) {
                    if ($i ~ /^AS[0-9]+/) {
                        as = $i
                    } else if ($i ~ /^\[.*\]$/) {
                        bracket = $i
                    } else {
                        desc = desc " " $i
                    }
                }
                # 去除 desc 开头的空格
                sub(/^ /, "", desc)
                # Get the first millisecond value from the next line
                getline next_line
                if (next_line ~ /[0-9]+\.[0-9]+ ms/) {
                    match(next_line, /[0-9]+\.[0-9]+ ms/)
                    ms = substr(next_line, RSTART, RLENGTH)
                    gsub(/ /, "", ms)
                }
                # Print the formatted result
                printf "|%s|%s|%s|%s|%s|%s|%s|\n", rnum, hop, ms, ip, as, bracket, desc
            }
        }
    }'
}
get_route_mode(){
ibar_step=19
local temp_info="$Font_Cyan$Font_B${sinfo[moderoute]}$Font_Suffix"
((ibar_step+=1))
show_progress_bar "$temp_info" $((50-${sinfo[lmoderoute]}))&
bar_pid="$!"&&disown "$bar_pid"
trap "kill_progress_bar" RETURN
local ipv=$1
local rdomain
rmresu=()
rmcode[0]=31
if [[ -z $mode_route_pv ]];then
rmtestnum=9
rmcode[1]=11
rmcode[2]=11
rmcode[3]=11
rmcode[4]=31
rmcode[5]=31
rmcode[6]=31
rmcode[7]=44
rmcode[8]=44
rmcode[9]=44
rdomain[0]="sh-ct-v$ipv.ip.zstaticcdn.com"
rdomain[1]="bj-ct-v$ipv.ip.zstaticcdn.com"
rdomain[2]="bj-cu-v$ipv.ip.zstaticcdn.com"
rdomain[3]="bj-cm-v$ipv.ip.zstaticcdn.com"
rdomain[4]="sh-ct-v$ipv.ip.zstaticcdn.com"
rdomain[5]="sh-cu-v$ipv.ip.zstaticcdn.com"
rdomain[6]="sh-cm-v$ipv.ip.zstaticcdn.com"
rdomain[7]="gd-ct-v$ipv.ip.zstaticcdn.com"
rdomain[8]="gd-cu-v$ipv.ip.zstaticcdn.com"
rdomain[9]="gd-cm-v$ipv.ip.zstaticcdn.com"
else
rmtestnum=3
rmcode[1]="$mode_route_pv"
rmcode[2]="$mode_route_pv"
rmcode[3]="$mode_route_pv"
rdomain[0]="sh-ct-v$ipv.ip.zstaticcdn.com"
rdomain[1]="${pcode[$mode_route_pv]}-ct-v$ipv.ip.zstaticcdn.com"
rdomain[2]="${pcode[$mode_route_pv]}-cu-v$ipv.ip.zstaticcdn.com"
rdomain[3]="${pcode[$mode_route_pv]}-cm-v$ipv.ip.zstaticcdn.com"
fi
local max_threads=18
local available_memory=1024
[[ "$(uname)" != "Darwin" ]]&&available_memory=$(free -m|awk '/Mem:/ {print $7}')
local max_threads_by_memory=$(echo "$available_memory / 28"|bc)
((max_threads_by_memory<max_threads))&&max_threads=$max_threads_by_memory
local current_threads=0
local tmpresult=$(for i in $(seq 0 $rmtestnum)
do
local protocol=1
nexttrace_route "${rdomain[$i]}" "$protocol" "$i" "$ipv"&
((current_threads++))
if ((current_threads>=max_threads));then
wait -n
((current_threads--))
else
sleep 2
fi
done
wait)
rmmaxhop=()
rmcnhop=()
rmallasn=()
rmallgeo=()
while IFS= read -r line;do
[[ -z $line ]]&&continue
IFS='|' read -ra fields <<<"$line"
i1=$(printf "%02d" "${fields[1]}")
i2=$(printf "%02d" "${fields[2]}")
rmresu["$i1${i2}1"]="${fields[3]}"
rmresu["$i1${i2}2"]=$(mask_ip "${fields[4]}")
rmresu["$i1${i2}3"]="${fields[5]}"
rmresu["$i1${i2}4"]="${fields[6]}"
rmresu["$i1${i2}5"]="${fields[7]}"
rmresu["$i1${i2}6"]=$(extract_region "${rmresu[$i1${i2}5]}")
[[ ${rmresu["$i1${i2}2"]} == 59.43.* ]]&&rmresu["$i1${i2}3"]="AS4809"
[[ ${rmresu["$i1${i2}5"]} == *CTGNet* ]]&&rmresu["$i1${i2}3"]="AS23764"
if [[ -z ${rmcnhop["$i1"]} ]]&&[[ ${rmresu["$i1${i2}5"]} == *中国* ]]&&[[ ${rmresu["$i1${i2}5"]} != *香港* ]]&&[[ ${rmresu["$i1${i2}5"]} != *澳门* ]]&&[[ ${rmresu["$i1${i2}5"]} != *台湾* ]];then
rmcnhop["$i1"]="$i2"
fi
if [[ -n ${rmresu[$i1${i2}6]} ]];then
if [[ ${rmallgeo[$i1]} == *"${rmresu[$i1${i2}6]}"* ]];then
rmallgeo[$i1]="${rmallgeo[$i1]%${rmresu[$i1${i2}6]}*}${rmresu[$i1${i2}6]}"
else
[[ -n ${rmallgeo[$i1]} ]]&&rmallgeo[$i1]="${rmallgeo[$i1]} -> "
rmallgeo[$i1]="${rmallgeo[$i1]}${rmresu[$i1${i2}6]}"
fi
fi
if [[ ${rmallgeo[$i1]} != *"${rmresu[$i1${i2}6]}" ]];then
[[ -n ${rmallgeo[$i1]} ]]&&rmallgeo[$i1]="${rmallgeo[$i1]} -> "
rmallgeo[$i1]="${rmallgeo[$i1]}${rmresu[$i1${i2}6]}"
fi
if [[ -n ${rmresu["$i1${i2}3"]} && ${rmallasn[$i1]} != *"${rmresu[$i1${i2}3]}" ]];then
[[ -n ${rmallasn["$i1"]} ]]&&rmallasn["$i1"]="${rmallasn["$i1"]} -> "
rmallasn["$i1"]="${rmallasn["$i1"]}${rmresu[$i1${i2}3]}"
fi
local vara=${i2#0}
local varb="${rmmaxhop["$i1"]:-0}"
varb=${varb#0}
if ((vara>varb));then
rmmaxhop["$i1"]="$i2"
fi
done <<<"$tmpresult"
rmcn=()
rmww=()
for i in $(seq 0 $rmtestnum);do
ii=$(printf "%02d" "$i")
rmcn[$ii]="Unknown"
rmww[$ii]="Unknown"
[[ ${rmcnhop[$ii]} == 0 || ${rmcnhop[$ii]} == ${rmmaxhop[$ii]} ]]&&rmcn[$ii]="Hidden"
local vara="${rmcnhop[$ii]:-0}"
vara=${vara#0}
[[ ${rmresu[$ii${rmcnhop[$ii]}3]} == "AS17676" ]]&&rmcnhop[$ii]=$(printf "%02d" "$((vara+1))")
case "${rmresu[$ii${rmcnhop[$ii]}3]}" in
"AS4134")rmcn[$ii]="163"
;;
"AS4837")rmcn[$ii]="4837"
local vara="${rmcnhop[$ii]:-0}"
vara=${vara#0}
if ((vara>1));then
varb=$(printf "%02d" "$((vara-1))")
[[ ${rmresu[$ii${varb}3]} == "AS10099" ]]&&rmcn[$ii]="10099"
fi
;;
"AS58453")rmcn[$ii]="CMI"
;;
"AS58807")rmcn[$ii]="CMIN2"
;;
"AS9808")rmcn[$ii]="CMI"
[[ ${rmallasn[$ii]} == *AS58807* ]]&&rmcn[$ii]="CMIN2"
;;
"AS9929")rmcn[$ii]="9929"
;;
"AS10099")rmcn[$ii]="10099"
[[ ${rmallasn[$ii]} == *AS9929* ]]&&rmcn[$ii]="9929"
;;
"AS4809")rmcn[$ii]="CN2GIA"
local vara="${rmcnhop[$ii]:-0}"
local varb="${rmmaxhop[$ii]:-0}"
vara=${vara#0}
varb=${varb#0}
if ((vara>1));then
[[ ${rmallasn[$ii]} == *AS23764* ]]&&rmcn[$ii]="CTGGIA"
fi
if [[ $rmgia -ne 1 ]];then
for ((thop=vara; thop<=varb; thop++));do
hop=$(printf "%02d" "$thop")
[[ ${rmresu[$ii${hop}3]} == "AS4809" || ${rmresu[$ii${hop}3]} == "AS23764" ]]&&continue
if [[ ${rmresu[$ii${hop}2]} == 202.97* ]];then
rmcn[$ii]="CN2GT"
fi
break
done
fi
;;
"AS23764")rmcn[$ii]="CTGGIA"
if [[ $rmgia -ne 1 ]];then
local vara="${rmcnhop[$ii]:-0}"
local varb="${rmmaxhop[$ii]:-0}"
vara=${vara#0}
varb=${varb#0}
for ((thop=vara; thop<=varb; thop++));do
hop=$(printf "%02d" "$thop")
[[ ${rmresu[$ii${hop}3]} == "AS4809" || ${rmresu[$ii${hop}3]} == "AS23764" ]]&&continue
if [[ ${rmresu[$ii${hop}2]} == 202.97* ]];then
rmcn[$ii]="CN2GT"
fi
break
done
fi
;;
"AS4538")rmcn[$ii]="CERNET"
;;
"AS7497")rmcn[$ii]="CSTNET"
;;
*)rmcn[$ii]="NoData"
if [[ ${rmallasn[$ii]} == *AS58807* ]];then
rmcn[$ii]="CMIN2"
elif [[ ${rmallasn[$ii]} == *AS9929* ]];then
rmcn[$ii]="9929"
elif [[ ${rmallasn[$ii]} == *AS10099* ]];then
rmcn[$ii]="10099"
elif [[ ${rmallasn[$ii]} == *AS4809* ]];then
rmcn[$ii]="CN2"
elif [[ ${rmallasn[$ii]} == *AS9808* ]];then
rmcn[$ii]="CMI"
elif [[ ${rmallasn[$ii]} == *AS4134* ]];then
rmcn[$ii]="163"
elif [[ ${rmallasn[$ii]} == *AS4837* ]];then
rmcn[$ii]="4837"
fi
esac
[[ ${rmcn[$ii]} == *GIA ]]&&rmgia=1
local vara="${rmcnhop[$ii]:-0}"
vara=${vara#0}
for ((thop=vara-1; thop>0; thop--));do
hop=$(printf "%02d" "$thop")
if [[ -n ${rmresu[$ii${hop}3]} && ${rmresu[$ii${hop}3]} != "AS58453" && ${rmresu[$ii${hop}3]} != "AS58807" && ${rmresu[$ii${hop}3]} != "AS4837" && ${rmresu[$ii${hop}3]} != "AS10099" && ${rmresu[$ii${hop}3]} != "AS9929" && ${rmresu[$ii${hop}3]} != "AS4134" && ${rmresu[$ii${hop}3]} != "AS4809" && ${rmresu[$ii${hop}3]} != "AS4808" && ${rmresu[$ii${hop}3]} != "AS23764" && ${rmresu[$ii${hop}3]} != "AS4538" && ${rmresu[$ii${hop}3]} != "AS7497" ]];then
rmww[$ii]="${rmresu[$ii${hop}3]}"
break
fi
done
if [[ -n ${rmww[$ii]} ]];then
[[ -n ${AS_MAPPING[${rmww[$ii]}]} ]]&&rmww[$ii]="${AS_MAPPING[${rmww[$ii]}]}"
fi
done
}
parse_iperf3_result(){
local server=$1
local portl=$2
local portu=$3
local ipv="-4"
[[ $4 -eq 6 ]]&&ipv="-6"
local sendrecv=""
[[ $5 -eq 1 ]]&&sendrecv=" -R"
local maxtry=5
local port=0
iperfresu[s]=-1
iperfresu[r]=-1
local infolen
if [[ $YY == "cn" ]];then
infolen=$((${#6}*2))
else
infolen=${#6}
fi
local temp_info="$Font_Cyan$Font_B${sinfo[iperf]}$6$Font_Suffix"
((ibar_step+=2))
show_progress_bar "$temp_info" $((50-${sinfo[liperf]}-infolen))&
bar_pid="$!"&&disown "$bar_pid"
trap "kill_progress_bar" RETURN
for ((i=1; i<=maxtry; i++));do
port=$((RANDOM%(portu-portl+1)+portl))
local response=$(timeout 20 iperf3 $ipv$sendrecv -J -t 6 -c "$server" -p "$port" 2>&1)
if [[ -n $response && $response != *"iperf3: error"* && $response != *"\"error\":"* ]];then
local bits_per_second=$(echo "$response"|jq -r '.end.sum_received.bits_per_second')
local retransmits=$(echo "$response"|jq -r '.end.sum_sent.retransmits')
if [[ -n $bits_per_second && $bits_per_second != "null" && -n $retransmits && $retransmits != "null" ]];then
iperfresu[s]=$bits_per_second
iperfresu[r]=$retransmits
return 0
fi
fi
done
return 1
}
convert_b2m(){
local bps=$1
local mbps
local color
if (($(echo "$bps < 0"|bc -l)));then
echo -e "$Font_Red     E$Font_Suffix"
return
else
mbps=$(echo "$bps / 1000000"|bc)
fi
if [ "$mbps" -gt 99999 ];then
echo -e "$Font_Green ${Font_U}100G+$Font_Suffix"
return
fi
if [ "$mbps" -lt 50 ];then
color=$Font_Red
elif [ "$mbps" -ge 50 ]&&[ "$mbps" -lt 200 ];then
color=$Font_Yellow
elif [ "$mbps" -ge 200 ];then
color=$Font_Green
else
color=$Font_Red
fi
local tmp_space=$((6-${#mbps}))
echo "$color$(printf "%${tmp_space}s\n")$Font_U$mbps$Font_Suffix"
}
convert_retr(){
local num=$1
local color
local result
if [ "$num" -lt 0 ];then
echo -e "${Font_Red}RROR$Font_Suffix"
return
fi
if [[ $num -eq 0 ]];then
color=$Font_Green
elif [[ $num -ge 1 && $num -le 99 ]];then
color=$Font_Yellow
elif [[ $num -gt 99 ]];then
color=$Font_Red
else
color=$Font_Red
fi
if [[ $num -lt 1000 ]];then
result=$num
elif [[ $num -ge 1000 && $num -lt 10000 ]];then
result="${num:0:1}k"
elif [[ $num -ge 10000 && $num -lt 100000 ]];then
result="${num:0:2}k"
elif [[ $num -ge 100000 && $num -lt 1000000 ]];then
result=".${num:0:1}m"
else
result="1m+"
fi
echo "$color$(printf '%4s' "$result")$Font_Suffix"
}
process_wwpingtestresult(){
local testresult=$1
local -A midresu
local -A midresu2
local tmp_space
local ipv
local index
local numbers
local total
local count
local lost
local result
IFS=$'\n' read -r -d '' -a lines <<<"$testresult"
for line in "${lines[@]}";do
line=$(echo "$line"|xargs)
[[ -z $line ]]&&continue
IFS=' ' read -ra parts <<<"$line"
index="${parts[1]}${parts[2]}${parts[3]}"
ipv="${parts[2]}"
ipout[$index]="${parts[4]}"
done
local keys=($(echo "${!icity[@]}"|tr ' ' '\n'|sort -n))
for key in "${keys[@]}";do
total=0
count=0
lost=""
for i in $(seq 1 $pingww_test_count);do
numbers=${ipout[$key$ipv$i]}
if [[ $numbers =~ ^0\.0*$ ]];then
lost="$Font_Red"
else
total=$(echo "$total + $numbers"|bc)
((count++))
fi
done
if ((count>0));then
local avg=$(echo "scale=0; $total / $count"|bc)
else
local avg=0
fi
result=""
for ((i=1; i<pingww_test_count; i+=2));do
local A="${ipout[$key$ipv$i]}"
local B="${ipout[$key$ipv$((i+1))]}"
local char=$(calculate_delay "$A" "$B")
result+="$char"
done
if [[ $avg -gt 240 || $lost == "$Font_Red" ]];then
lost="$Font_Red"
elif [[ $avg -gt 150 ]];then
lost="$Font_Yellow"
elif [[ $avg -le 150 ]];then
lost="$Font_Green"
else
lost="$Font_Red"
fi
iavg[$key]="$avg"
midresu[$key$ipv]="$Font_Green$result$lost$Font_B$(printf '%3s' "$avg")$Font_Suffix"
if [[ $YY == "cn" ]];then
tmp_space=$((10-${#icity[$key]}*2))
else
tmp_space=$((10-${#icity[$key]}))
fi
if [[ $mode_low -eq 1 ]];then
iresu[$key]="$Font_Cyan${icity[$key]}$(printf "%${tmp_space}s\n")${midresu[$key$ipv]}        ${Font_Green}SKIP$Font_Suffix        "
else
iresu[$key]="$Font_Cyan${icity[$key]}$(printf "%${tmp_space}s\n")${midresu[$key$ipv]}$(convert_b2m ${isout[$key${ipv}1]})$(convert_retr ${isout[$key${ipv}2]})$(convert_b2m ${isout[$key${ipv}3]})$(convert_retr ${isout[$key${ipv}4]})"
fi
done
}
iperf_test(){
ibar_step=48
local ipv=$1
local port=0
local json_data=$(curl -sL "${rawgithub}main/ref/iperf.json")
while IFS=" " read -r code server portl portu city cityzh;do
if [[ $YY == "cn" ]];then
icity["$code"]="$cityzh"
else
icity["$code"]="$city"
fi
idm["$code"]="$server"
iportl["$code"]="$portl"
iportu["$code"]="$portu"
done < <(echo "$json_data"|jq -r '.[] | "\(.code) \(.server) \(.portl) \(.portu) \(.city) \(.cityzh)"')
local keys=($(echo "${!icity[@]}"|tr ' ' '\n'|sort -n))
if [[ $mode_low -eq 0 ]];then
for key in "${keys[@]}";do
parse_iperf3_result "${idm[$key]}" ${iportl[$key]} ${iportu[$key]} $ipv 0 "${icity[$key]}${siperf[send]}"
isout["$key${ipv}1"]=${iperfresu[s]}
isout["$key${ipv}2"]=${iperfresu[r]}
parse_iperf3_result "${idm[$key]}" ${iportl[$key]} ${iportu[$key]} $ipv 1 "${icity[$key]}${siperf[recv]}"
isout["$key${ipv}3"]=${iperfresu[s]}
isout["$key${ipv}4"]=${iperfresu[r]}
done
fi
local temp_info="$Font_Cyan$Font_B${sinfo[delayww]}$Font_Suffix"
((ibar_step+=2))
show_progress_bar "$temp_info" $((50-${sinfo[ldelayww]}))&
bar_pid="$!"&&disown "$bar_pid"
trap "kill_progress_bar" RETURN
local max_threads=10
local available_memory=1024
[[ "$(uname)" != "Darwin" ]]&&available_memory=$(free -m|awk '/Mem:/ {print $7}')
local max_threads_by_memory=$(echo "$available_memory / 8"|bc)
((max_threads_by_memory<max_threads))&&max_threads=$max_threads_by_memory
local current_threads=0
local tmpresult=$(for i in $(seq 1 $pingww_test_count)
do
for key in "${keys[@]}";do
if [[ $key -eq 41 ]];then
ping_test "speedtest.fra1.de.leaseweb.net" "TCP" 1400 "$i" "${icity[$key]}" "$key" "$ipv"&
elif [[ $key -eq 43 ]];then
ping_test "speedtest.ams1.nl.leaseweb.net" "TCP" 1400 "$i" "${icity[$key]}" "$key" "$ipv"&
else
ping_test "${idm[$key]}" "TCP" 1400 "$i" "${icity[$key]}" "$key" "$ipv"&
fi
((current_threads++))
if ((current_threads>=max_threads));then
wait -n
((current_threads--))
fi
done
done
wait)
process_wwpingtestresult "$tmpresult"
}
show_iperf(){
echo -ne "\r${siperf[title]}\n"
local count=0
local keys=($(echo "${!icity[@]}"|tr ' ' '\n'|sort -n))
for key in "${keys[@]}";do
((count++))
if ((count%2==0));then
echo -ne "${iresu[$key]}\n"
else
echo -ne "\r${iresu[$key]}||"
fi
done
((count%2!=0))&&echo
}
parse_speedtest_result(){
local tid="$1"
local tcode="$2"
local infolen
if [[ $YY == "cn" ]];then
infolen=$((${#scity[$tcode]}*2+${#spv[$tcode]}*2))
infotxt="${scity[$tcode]}${spv[$tcode]}"
else
infolen=$((${#scity[$tcode]}+${#spv[$tcode]}+1))
infotxt="${scity[$tcode]} ${spv[$tcode]}"
fi
local temp_info="$Font_Cyan$Font_B${sinfo[speedtest]}$infotxt$Font_Suffix"
((ibar_step+=2))
show_progress_bar "$temp_info" $((50-${sinfo[lspeedtest]}-infolen))&
bar_pid="$!"&&disown "$bar_pid"
trap "kill_progress_bar" RETURN
local maxtry=1
sout["${tcode}1"]=-1
sout["${tcode}2"]=-1
sout["${tcode}3"]=-1
sout["${tcode}4"]=-1
local i
for ((i=1; i<=maxtry; i++));do
local response=$(speedtest --accept-gdpr --accept-license -f json -s "$tid" 2>&1)
response=$(echo "$response"|sed -n '/^{/,/^}/p')
if [[ -n $response && $response != *"[error]"* && $response != *"\"error\""* ]];then
local download_bandwidth=$(echo "$response"|jq '.download.bandwidth')
sout["${tcode}3"]=$((download_bandwidth*8))
local upload_bandwidth=$(echo "$response"|jq '.upload.bandwidth')
sout["${tcode}1"]=$((upload_bandwidth*8))
local download_latency_iqm=$(echo "$response"|jq '.download.latency.iqm')
sout["${tcode}4"]=${download_latency_iqm%.*}
local upload_latency_iqm=$(echo "$response"|jq '.upload.latency.iqm')
sout["${tcode}2"]=${upload_latency_iqm%.*}
return 0
fi
done
return 1
}
convert_delay(){
local num=$1
local color
local result
if [[ ! $num =~ ^-?[0-9]+$ ]];then
echo -e "$Font_Red     -$Font_Suffix"
return
fi
if [ "$num" -lt 0 ];then
echo -e "${Font_Red}RROR  $Font_Suffix"
return
fi
if [[ $num -eq 0 ]];then
color=$Font_Red
elif [[ $num -ge 1 && $num -le 150 ]];then
color=$Font_Green
elif [[ $num -ge 151 && $num -le 240 ]];then
color=$Font_Yellow
else
color=$Font_Red
fi
if [[ $num -lt 1000 ]];then
result=$num
elif [[ $num -ge 1000 && $num -lt 10000 ]];then
result="${num:0:1}k"
elif [[ $num -ge 10000 && $num -lt 100000 ]];then
result="${num:0:2}k"
elif [[ $num -ge 100000 && $num -lt 1000000 ]];then
result=".${num:0:1}m"
else
result="1m+"
fi
echo "$color$(printf '%6s' "$result")$Font_Suffix"
}
speedtest_test(){
ibar_step=36
local json_data=$(curl -sL "${rawgithub}main/ref/speedtest_cn.json")
declare -A codemax
codemax[1]=0
codemax[2]=0
codemax[3]=0
codemax[4]=0
while IFS=" " read -r code id city cityzh provider providerzh;do
if [[ $YY == "cn" ]];then
scity["$code"]="$cityzh"
spv["$code"]="$providerzh"
else
scity["$code"]="$city"
spv["$code"]="$provider"
fi
sid["$code"]="$id"
ten_digit="${code:0:1}"
one_digit="${code:1}"
if [[ $one_digit -gt ${codemax[$ten_digit]} ]];then
codemax["$ten_digit"]="$one_digit"
fi
done < <(echo "$json_data"|jq -r '.[] | "\(.code) \(.id) \(.city) \(.cityzh) \(.provider) \(.providerzh)"')
local skip
local key
local pvi
local pvj
for ((pvi=1; pvi<=3; pvi++));do
skip=0
for ((pvj=1; pvj<=2; pvj++));do
for ((try=1; codemax[$pvi]-3+pvj-skip>0; try++));do
key=$((pvj+skip))
parse_speedtest_result "${sid[$pvi$key]}" "$pvi$key"
if [[ sout[$pvi${key}1] -eq -1 && sout[$pvi${key}2] -eq -1 && sout[$pvi${key}3] -eq -1 && sout[$pvi${key}4] -eq -1 ]];then
((skip++))
((ibar_step-=2))
else
break
fi
done
if [[ $YY == "cn" ]];then
tmp_space=$((13-${#scity[$pvi$key]}*2-${#spv[$pvi$key]}*2))
sresu[$pvi$pvj]="$Font_Cyan${scity[$pvi$key]}${spv[$pvi$key]}$(printf "%${tmp_space}s\n")"
else
tmp_space=$((10-${#scity[$pvi$key]}))
sresu[$pvi$pvj]="$Font_Cyan${scity[$pvi$key]}$(printf "%${tmp_space}s\n")${spv[$pvi$key]} $Font_Suffix"
fi
sresu[$pvi$pvj]+="$(convert_b2m ${sout[$pvi${key}1]})$(convert_delay ${sout[$pvi${key}2]})  $(convert_b2m ${sout[$pvi${key}3]})$(convert_delay ${sout[$pvi${key}4]})"
done
done
}
show_speedtest(){
echo -ne "\r${sspeedtest[title]}\n"
local count=0
local keys=($(echo "${!sresu[@]}"|tr ' ' '\n'|sort -n))
for key in "${keys[@]}";do
((count++))
if ((count%2==0));then
echo -ne "${sresu[$key]}\n"
else
echo -ne "\r${sresu[$key]}||"
fi
done
((count%2!=0))&&echo
}
show_head(){
echo -ne "\r$(printf '%80s'|tr ' ' '*')\n"
if [ $fullIP -eq 1 ];then
calc_padding "$(printf '%*s' "${shead[ltitle]}" '')$IP" 80
echo -ne "\r$PADDING$Font_B${shead[title]}$Font_Cyan$IP$Font_Suffix\n"
else
calc_padding "$(printf '%*s' "${shead[ltitle]}" '')$IPhide" 80
echo -ne "\r$PADDING$Font_B${shead[title]}$Font_Cyan$IPhide$Font_Suffix\n"
fi
calc_padding "${shead[git]}" 80
echo -ne "\r$PADDING$Font_U${shead[git]}$Font_Suffix\n"
calc_padding "${shead[bash]}" 80
echo -ne "\r$PADDING${shead[bash]}\n"
echo -ne "\r${shead[ptime]}${shead[time]}  ${shead[ver]}\n"
echo -ne "\r$(printf '%80s'|tr ' ' '*')\n"
}
show_bgp(){
echo -ne "\r${sbgp[title]}\n"
if [[ -n ${bgp[asn]} && ${bgp[asn]} != "null" || -n ${bgp[org]} && ${bgp[org]} != "null" || -n ${bgp[prefixnum]} && ${bgp[prefixnum]} != "null" || -n ${bgp[rir]} && ${bgp[rir]} != "null" ]];then
local tmpstr=""
local tmpinfo=""
[[ -n ${bgp[rir]} && ${bgp[rir]} != "null" ]]&&tmpinfo="${bgp[rir]}"&&tmpstr=", "
[[ -n ${bgp[asn]} && ${bgp[asn]} != "null" ]]&&tmpinfo="$tmpinfo$tmpstr${bgp[asn]}"&&tmpstr=" "
[[ -n ${bgp[org]} && ${bgp[org]} != "null" ]]&&tmpinfo="$tmpinfo$tmpstr${bgp[org]}"&&tmpstr=", "
[[ $tmpstr == " " ]]&&tmpstr=", "
[[ -n ${bgp[prefixnum]} && ${bgp[prefixnum]} != "null" ]]&&tmpinfo="$tmpinfo${tmpstr}Prefix/${bgp[prefixnum]}"
echo -ne "\r$Font_Cyan${sbgp[ipinfo]}$Font_Green$(wrap_text 20 "$tmpinfo")$Font_Suffix\n"
fi
if [[ -n ${bgp[regdate]} && -n ${bgp[moddate]} ]];then
echo -ne "\r$Font_Cyan${sbgp[date]}$Font_Green${bgp[regdate]} / ${bgp[moddate]}$Font_Suffix\n"
elif [[ -n ${bgp[regdate]} && -z ${bgp[moddate]} ]];then
echo -ne "\r$Font_Cyan${sbgp[date]}$Font_Green${bgp[regdate]} / NoRecord$Font_Suffix\n"
elif [[ -z ${bgp[regdate]} && -n ${bgp[moddate]} ]];then
echo -ne "\r$Font_Cyan${sbgp[date]}${Font_Green}NoRecord / ${bgp[moddate]}$Font_Suffix\n"
fi
if [[ -n ${bgp[countrycode]} && ${bgp[countrycode]} != "null" ]];then
local fullcountry="[${bgp[countrycode]}]"
[[ -n ${bgp[country]} ]]&&fullcountry="$fullcountry${bgp[country]}"
if [[ -n ${bgp[intermediateregion]} ]];then
fullcountry="$fullcountry, ${bgp[intermediateregion]}"
elif [[ -n ${bgp[subregion]} ]];then
fullcountry="$fullcountry, ${bgp[subregion]}"
fi
[[ -n ${bgp[region]} ]]&&fullcountry="$fullcountry, ${bgp[region]}"
fi
[[ -n $fullcountry && $fullcountry != "null" ]]&&echo -ne "\r$Font_Cyan${sbgp[country]}$Font_Green$(wrap_text 20 "$fullcountry")$Font_Suffix\n"
[[ -n ${bgp[address]} && ${bgp[address]} != "null" ]]&&echo -ne "\r$Font_Cyan${sbgp[address]}$Font_Green$(wrap_text 20 "${bgp[address]}")$Font_Suffix\n"
[[ -n ${bgp[geofeed]} && ${bgp[geofeed]} != "null" ]]&&echo -ne "\r$Font_Cyan${sbgp[geofeed]}$Font_Green${bgp[geofeed]}$Font_Suffix\n"
local neighborresu=""
if [[ ${bgp[neighbortotal]} -gt 0 && -n ${bgp[neighboractive]} ]];then
neighbor_ratio=$(echo "scale=2; ${bgp[neighboractive]}/${bgp[neighbortotal]}"|bc)
if (($(echo "$neighbor_ratio < 0.5"|bc -l)));then
neighbor_bg=$Back_Green
elif (($(echo "$neighbor_ratio >= 0.5"|bc -l)))&&(($(echo "$neighbor_ratio < 0.8"|bc -l)));then
neighbor_bg=$Back_Yellow
elif (($(echo "$neighbor_ratio >= 0.8"|bc -l)));then
neighbor_bg=$Back_Red
else
neighbor_bg=$Back_Green
fi
neighborresu="${Font_Green}Subnet/24 $neighbor_bg$Font_B$Font_White ${bgp[neighboractive]} / ${bgp[neighbortotal]} $Font_Suffix    "
fi
if [[ ${bgp[iptotal]} -gt 0 && -n ${bgp[ipactive]} ]];then
ip_ratio=$(echo "scale=2; ${bgp[ipactive]}/${bgp[iptotal]}"|bc)
if (($(echo "$ip_ratio < 0.5"|bc -l)));then
ip_bg=$Back_Green
elif (($(echo "$ip_ratio >= 0.5"|bc -l)))&&(($(echo "$ip_ratio < 0.8"|bc -l)));then
ip_bg=$Back_Yellow
elif (($(echo "$ip_ratio >= 0.8"|bc -l)));then
ip_bg=$Back_Red
else
ip_bg=$Back_Green
fi
neighborresu+="${Font_Green}Prefix/${bgp[prefixnum]} $ip_bg$Font_B$Font_White ${bgp[ipactive]} / ${bgp[iptotal]} $Font_Suffix"
fi
[[ -n $neighborresu ]]&&echo -ne "\r$Font_Cyan${sbgp[neighbor]}$neighborresu$Font_Suffix\n"
}
show_local(){
echo -ne "\r${slocal[title]}\n"
[[ -n ${getnat[type]} ]]&&echo -ne "\r$Font_Cyan${slocal[nat]}${slocal[${getnat[type]}]}$Font_Suffix\n"
if [[ ${getnat[char]} -eq 1 ]];then
echo -ne "\r$Font_Cyan${slocal[mapping]}${slocal[m${getnat[m]}]}$Font_Suffix$Font_Cyan${slocal[filter]}${slocal[f${getnat[f]}]}$Font_Suffix$Font_Cyan${slocal[port]}${slocal[p${getnat[p]}]}$Font_Suffix$Font_Cyan${slocal[hairpin]}${slocal[h${getnat[h]}]}$Font_Suffix\n"
fi
echo -ne "\r$Font_Cyan${slocal[tcpcc]}$Font_Green$(printf '%-13s' "${gettcp[tcpcc]}")$Font_Cyan${slocal[rmem]}$Font_Green${gettcp[rmem]}$Font_Suffix\n"
echo -ne "\r$Font_Cyan${slocal[qdisc]}$Font_Green$(printf '%-13s' "${gettcp[qdisc]}")$Font_Cyan${slocal[wmem]}$Font_Green${gettcp[wmem]}$Font_Suffix\n"
}
show_conn(){
echo -ne "\r${sconn[title]}\n"
if [[ ${conn[ix]} -eq 99 ]];then
echo -ne "\r$Font_Cyan${sconn[ix]}$Font_Green$(printf '%-10s' "${conn[ix]}+")"
elif [[ ${conn[ix]} -eq -1 ]];then
echo -ne "\r$Font_Cyan${sconn[ix]}$Font_Green$(printf '%-10s' "-")"
else
echo -ne "\r$Font_Cyan${sconn[ix]}$Font_Green$(printf '%-10s' "${conn[ix]}")"
fi
if [[ ${conn[upstreams]} -eq -2 ]];then
echo -ne "$Font_Cyan${sconn[upstreams]}${Font_Green}Transit-Free  \n"
elif [[ ${conn[upstreams]} -eq -1 ]];then
echo -ne "$Font_Cyan${sconn[upstreams]}$Font_Green$(printf '%-10s' "-")"
else
echo -ne "$Font_Cyan${sconn[upstreams]}$Font_Green$(printf '%-10s' "${conn[upstreams]}")"
fi
if [[ ${conn[peers]} -eq -1 ]];then
echo -ne "$Font_Cyan${sconn[peers]}$Font_Green-$Font_Suffix\n"
else
echo -ne "$Font_Cyan${sconn[peers]}$Font_Green${conn[peers]}$Font_Suffix\n"
fi
local clenth=0
conn[asn]=""
conn[org]=""
for id in $(echo "${!casn[@]}"|tr ' ' '\n'|sort -n);do
local raw_as_number="AS${casn[$id]}"
local raw_as_name="${corg[$id]}"
if [[ ${casn[$id]} -eq 0 || ${ctarget[$id]} == "true" ]];then
continue
fi
local len_as_number=${#raw_as_number}
local len_as_name=${#raw_as_name}
local max_len=$((len_as_number>len_as_name?len_as_number:len_as_name))
if ((len_as_number<max_len));then
local spaces_to_add=$((max_len-len_as_number))
local left_spaces=$((spaces_to_add/2))
local right_spaces=$((spaces_to_add-left_spaces))
raw_as_number="$(printf "%*s%s%*s" "$left_spaces" "" "$raw_as_number" "$right_spaces" "")"
fi
if ((len_as_name<max_len));then
local spaces_to_add=$((max_len-len_as_name))
local right_spaces=$((spaces_to_add/2))
local left_spaces=$((spaces_to_add-right_spaces))
raw_as_name="$(printf "%*s%s%*s" "$left_spaces" "" "$raw_as_name" "$right_spaces" "")"
fi
local as_number_style=""
local as_name_style=""
local reset_style="$Font_Suffix"
[[ ${cupstream[$id]} == "true" ]]&&as_name_style+="$Font_U"
as_number_style+="$Font_B"
as_name_style+="$Font_B"
as_number_style+="$Font_White$Back_Blue"
[[ ${ctier1[$id]} == "true" ]]&&as_name_style+="$Font_White$Back_Green"
[[ ${ctier1[$id]} == "false" ]]&&as_name_style+="$Font_White$Back_Yellow"
local as_number="$as_number_style$raw_as_number$reset_style"
local as_name="$as_name_style$raw_as_name$reset_style"
clenth=$((clenth+max_len+1))
if ((clenth>81));then
clenth=$((max_len+1))
echo -ne "\r${conn[asn]}\n\r${conn[org]}\n"
conn[asn]="$as_number "
conn[org]="$as_name "
else
conn[asn]="${conn[asn]}$as_number "
conn[org]="${conn[org]}$as_name "
fi
done
[[ -n ${conn[asn]} ]]&&echo -ne "\r${conn[asn]}\n"
[[ -n ${conn[org]} ]]&&echo -ne "\r${conn[org]}\n"
}
show_tail(){
echo -ne "\r$(printf '%80s'|tr ' ' '=')\n"
echo -ne "\r$Font_I${stail[stoday]}${stail[today]}${stail[stotal]}${stail[total]}${stail[thanks]} $Font_Suffix\n"
echo -e ""
}
get_opts(){
local args=()
while [[ $# -gt 0 ]];do
case "$1" in
-[loSR])args+=("$1")
if [[ $# -gt 1 && $2 != -* ]];then
args+=("$2")
shift
fi
shift
;;
-[loSR]*)ERRORcode=1
shift
;;
-[46fhjnpyELMP]*)local opt="$1"
shift
for ((i=1; i<${#opt}; i++));do
args+=("-${opt:i:1}")
done
;;
--*|-*[!-]*)args+=("$1")
shift
;;
-*)ERRORcode=1
shift
;;
*)shift
esac
done
set -- "${args[@]}"
while [[ $# -gt 0 ]];do
case "$1" in
-4)if
[[ IPV4check -ne 0 ]]
then
IPV6check=0
else
ERRORcode=4
fi
shift
;;
-6)if
[[ IPV6check -ne 0 ]]
then
IPV4check=0
else
ERRORcode=6
fi
shift
;;
-f)fullIP=1
shift
;;
-h)show_help
shift
;;
-j)mode_json=1
shift
;;
-l)shift
[[ $1 == -* ]]&&ERRORcode=1&&break
YY=$(echo "$1"|tr '[:upper:]' '[:lower:]')
shift
;;
-n)mode_no=1
shift
;;
-o)shift
[[ $1 == -* ]]&&{
ERRORcode=1
break
}
mode_output=1
outputfile="$1"
[[ -z $outputfile ]]&&{
ERRORcode=1
break
}
[[ -e $outputfile ]]&&{
ERRORcode=10
break
}
touch "$outputfile" 2>/dev/null||{
ERRORcode=11
break
}
shift
;;
-p)mode_privacy=1
shift
;;
-y)mode_yes=1
shift
;;
-E)YY="en"
shift
;;
-L)mode_low=1
shift
;;
-M)mode_menu=1
shift
;;
-P)mode_ping=1
shift
;;
-R)mode_route=1
shift
if [[ $# -gt 0 && $1 != -* ]];then
mode_route_pv=$(echo "$1"|tr '[:upper:]' '[:lower:]'|sed 's/省//g; s/市//g; s/县//g; s/维吾尔//g; s/回族//g; s/壮族//g; s/自治区//g; s/特别行政区//g')
shift
fi
;;
-S)shift
if [[ $# -gt 0 ]];then
mode_skip="$1"
shift
else
ERRORcode=1
fi
;;
-*)ERRORcode=1
shift
;;
*)shift
esac
done
if [[ $mode_menu -eq 1 ]];then
if [[ $YY == "cn" ]];then
eval "bash <(curl -sL https://Check.Place) -N"
else
eval "bash <(curl -sL https://Check.Place) -EN"
fi
exit 0
fi
[[ $mode_ping -eq 1 ]]&&mode_skip+="567"
[[ $mode_low -eq 1 ]]&&mode_skip+="6"
[[ $mode_route -eq 1 ]]&&mode_skip+="467"
[[ $mode_ping -eq 1 && $mode_skip == *"4"* ]]&&ERRORcode=9
[[ $mode_route -eq 1 && $mode_skip == *"5"* ]]&&ERRORcode=9
[[ $mode_skip == *"1"* && $mode_skip == *"2"* && $mode_skip == *"3"* && $mode_skip == *"4"* && $mode_skip == *"5"* && $mode_skip == *"6"* && $mode_skip == *"7"* ]]&&ERRORcode=9
[[ $IPV4check -eq 1 && $IPV6check -eq 0 && $IPV4work -eq 0 ]]&&ERRORcode=40
[[ $IPV4check -eq 0 && $IPV6check -eq 1 && $IPV6work -eq 0 ]]&&ERRORcode=60
CurlARG="$useNIC$usePROXY"
}
show_help(){
echo -ne "\r$shelp\n"
exit 0
}
show_ad(){
RANDOM=$(date +%s)
local -a ads=()
local i=1
while :;do
local content
content=$(curl -fsL --max-time 5 "${rawgithub}main/ref/ad$i.ans")||break
ads+=("$content")
((i++))
done
local adCount=${#ads[@]}
local -a indices=()
for ((i=1; i<=adCount; i++));do indices+=("$i");done
for ((i=adCount-1; i>0; i--));do
local j=$((RANDOM%(i+1)))
local tmp=${indices[i]}
indices[i]=${indices[j]}
indices[j]=$tmp
done
local -a aad
aad[0]=$(curl -sL --max-time 5 "${rawgithub}main/ref/sponsor.ans")
for ((i=0; i<adCount; i++));do
aad[${indices[i]}]="${ads[i]}"
done
local rows cols
if ! read rows cols < <(stty size 2>/dev/null);then cols=0;fi
ADLines=0
print_pair(){
local left="$1" right="$2"
local -a L R
mapfile -t L <<<"$left"
mapfile -t R <<<"$right"
local i
for ((i=0; i<12; i++));do
printf "%-72s$Font_Suffix     %-72s\n" "${L[i]}" "${R[i]}" 1>&2
done
ADLines=$((ADLines+12))
}
print_block(){
echo "$1" 1>&2
ADLines=$((ADLines+12))
}
if [[ $cols -ge 150 ]];then
if ((adCount==0));then
print_block "${aad[0]}"
elif ((adCount%2==1));then
print_pair "${aad[0]}" "${aad[1]}"
local k
for ((k=2; k<=adCount; k+=2));do
print_pair "${aad[$k]}" "${aad[$((k+1))]}"
done
else
print_block "${aad[0]}"
local k
for ((k=1; k<=adCount; k+=2));do
print_pair "${aad[$k]}" "${aad[$((k+1))]}"
done
fi
else
echo "${aad[0]}" 1>&2
for ((i=1; i<=adCount; i++));do
echo "${aad[$i]}" 1>&2
done
ADLines=$(((adCount+1)*12))
fi
}
read_ref(){
ISO3166=$(curl -sL -m 10 "${rawgithub}main/ref/iso3166.json")
RESPONSE=$(curl -sL -m 10 "${rawgithub}main/ref/province.json")
while IFS=" " read -r province code short name;do
pcode[$province]=$code
pshort[$province]=$short
pname[$province]=$(echo "$name"|sed -E 's/(省|市|自治区|维吾尔|壮族|回族)//g')
pcode_lower=$(echo "$code"|tr '[:upper:]' '[:lower:]')
pdm[${province}14]="$pcode_lower-ct-v4.ip.zstaticcdn.com"
pdm[${province}24]="$pcode_lower-cu-v4.ip.zstaticcdn.com"
pdm[${province}34]="$pcode_lower-cm-v4.ip.zstaticcdn.com"
pdm[${province}16]="$pcode_lower-ct-v6.ip.zstaticcdn.com"
pdm[${province}26]="$pcode_lower-cu-v6.ip.zstaticcdn.com"
pdm[${province}36]="$pcode_lower-cm-v6.ip.zstaticcdn.com"
done < <(echo "$RESPONSE"|jq -r '.[] | select(.province < 70) | "\(.province) \(.code) \(.short) \(.name)"')
if [[ -n $mode_route_pv ]];then
lower_optarg="$mode_route_pv"
mode_route_pv=""
for province in "${!pcode[@]}";do
lower_pcode=$(echo "${pcode[$province]}"|tr '[:upper:]' '[:lower:]')
if [[ $lower_optarg == "$lower_pcode" || $lower_optarg == "${pshort[$province]}" || $lower_optarg == "${pname[$province]}" ]];then
mode_route_pv="$province"
break
fi
done
[[ -z $mode_route_pv ]]&&ERRORcode=21
fi
while read -r as name;do
AS_MAPPING["$as"]="$name"
done < <(curl -sL "${rawgithub}main/ref/AS_Mapping.txt")
}
save_json(){
local head_updates=""
local bgp_updates=""
local local_updates=""
local connectivity_updates=""
if [ $fullIP -eq 1 ];then
head_updates+=".Head |= map(. + { IP: \"${IP:-null}\" }) | "
else
head_updates+=".Head |= map(. + { IP: \"${IPhide:-null}\" }) | "
fi
head_updates+=".Head |= map(. + { Command: \"${shead[bash]:-null}\" }) | "
head_updates+=".Head |= map(. + { GitHub: \"${shead[git]:-null}\" }) | "
head_updates+=".Head |= map(. + { Time: \"${shead[time]:-null}\" }) | "
head_updates+=".Head |= map(. + { Version: \"${shead[ver]:-null}\" }) | "
local first_asn=$(echo "${bgp[asn]}"|awk -F',' '{print $1}'|sed 's/^AS//')
first_asn=${first_asn:-null}
bgp_updates+=".BGP |= map(. + { ASN: \"$first_asn\" }) | "
bgp_updates+=".BGP |= map(. + { Organization: \"${bgp[org]:-null}\" }) | "
bgp_updates+=".BGP |= map(. + { Prefix: ${bgp[prefixnum]:-null} }) | "
bgp_updates+=".BGP |= map(. + { RIR: \"${bgp[rir]:-null}\" }) | "
bgp_updates+=".BGP |= map(. + { RegDate: \"${bgp[regdate]:-null}\" }) | "
bgp_updates+=".BGP |= map(. + { ModDate: \"${bgp[moddate]:-null}\" }) | "
bgp_updates+=".BGP |= map(. + { Country: \"${bgp[country]:-null}\" }) | "
bgp_updates+=".BGP |= map(. + { IntermediateRegion: \"${bgp[intermediateregion]:-null}\" }) | "
bgp_updates+=".BGP |= map(. + { SubRegion: \"${bgp[subregion]:-null}\" }) | "
bgp_updates+=".BGP |= map(. + { Region: \"${bgp[region]:-null}\" }) | "
bgp_updates+=".BGP |= map(. + { Address: \"${bgp[address]:-null}\" }) | "
bgp_updates+=".BGP |= map(. + { GeoFeed: \"${bgp[geofeed]:-null}\" }) | "
if [[ -n ${bgp[iptotal]} && -n ${bgp[ipactive]} ]];then
bgp_updates+=".BGP |= map(. + { IPinTotal: ${bgp[iptotal]:-null} }) | "
bgp_updates+=".BGP |= map(. + { IPActive: ${bgp[ipactive]:-null} }) | "
bgp_updates+=".BGP |= map(. + { NeighborinTotal: ${bgp[neighbortotal]:-null} }) | "
bgp_updates+=".BGP |= map(. + { NeighborActive: ${bgp[neighboractive]:-null} }) | "
elif [[ -n ${bgp[neighbortotal]} && -n ${bgp[neighboractive]} ]];then
bgp_updates+=".BGP |= map(. + { IPinTotal: ${bgp[neighbortotal]:-null} }) | "
bgp_updates+=".BGP |= map(. + { IPActive: ${bgp[neighboractive]:-null} }) | "
bgp_updates+=".BGP |= map(. + { NeighborinTotal: ${bgp[neighbortotal]:-null} }) | "
bgp_updates+=".BGP |= map(. + { NeighborActive: ${bgp[neighboractive]:-null} }) | "
else
bgp_updates+=".BGP |= map(. + { IPinTotal: null }) | "
bgp_updates+=".BGP |= map(. + { IPActive: null }) | "
bgp_updates+=".BGP |= map(. + { NeighborinTotal: null }) | "
bgp_updates+=".BGP |= map(. + { NeighborActive: null }) | "
fi
local_updates+=".Local |= map(. + { NAT: \"${getnat[nat]:-null}\" }) | "
local_updates+=".Local |= map(. + { NATDescribe: \"$(echo -e "${slocal[${getnat[type]}]:-null}"|sed -E 's/\x1B\[[0-9;]*[a-zA-Z]//g'|xargs)\" }) | "
local_updates+=".Local |= map(. + { Mapping: \"$(echo -e "${slocal[m${getnat[m]}]:-null}"|sed -E 's/\x1B\[[0-9;]*[a-zA-Z]//g'|xargs)\" }) | "
local_updates+=".Local |= map(. + { Filter: \"$(echo -e "${slocal[f${getnat[f]}]:-null}"|sed -E 's/\x1B\[[0-9;]*[a-zA-Z]//g'|xargs)\" }) | "
local_updates+=".Local |= map(. + { Port: \"$(echo -e "${slocal[p${getnat[p]}]:-null}"|sed -E 's/\x1B\[[0-9;]*[a-zA-Z]//g'|xargs)\" }) | "
local_updates+=".Local |= map(. + { Hairpin: \"$(echo -e "${slocal[h${getnat[h]}]:-null}"|sed -E 's/\x1B\[[0-9;]*[a-zA-Z]//g'|xargs)\" }) | "
local_updates+=".Local |= map(. + { TCPCongestionControl: \"${gettcp[tcpcc]:-null}\" }) | "
local_updates+=".Local |= map(. + { QueueDiscipline: \"${gettcp[qdisc]:-null}\" }) | "
local_updates+=".Local |= map(. + { TCPReceiveBuffer: \"${gettcp[rmem]:-null}\" }) | "
local_updates+=".Local |= map(. + { TCPSendBuffer: \"${gettcp[wmem]:-null}\" }) | "
bgp_updates+=".BGP |= map(. + { IXCount: ${conn[ix]:-null} }) | "
bgp_updates+=".BGP |= map(. + { UpstreamsCount: ${conn[upstreams]:-null} }) | "
bgp_updates+=".BGP |= map(. + { PeersCount: ${conn[peers]:-null} }) | "
for id in $(echo "${!casn[@]}"|tr ' ' '\n'|sort -n);do
if [[ -z ${casn[$id]} ]];then
continue
fi
connectivity_updates+=".Connectivity += [{\"ID\": $id, \"ASN\": ${casn[$id]:-null}, \"Org\": \"${corg[$id]:-null}\", \"IsTarget\": $([[ ${ctarget[$id]} == "true" ]]&&echo true||echo false), \"IsTier1\": $([[ ${ctier1[$id]} == "true" ]]&&echo true||echo false), \"IsUpstream\": $([[ ${cupstream[$id]} == "true" ]]&&echo true||echo false)}] | "
done
netdata=$(echo "$netdata"|jq "$head_updates$bgp_updates$local_updates$connectivity_updates.")
local delay_objects=()
local keys=($(echo "${!pcode[@]}"|tr ' ' '\n'|sort -n))
for key in "${keys[@]}";do
delay_object="{
            \"Code\": \"${pcode[$key]:-null}\",
            \"Name\": \"${pshort[$key]:-null}\",
            \"CT\": {
                \"Average\": \"${pavg[${key}1$1]:-null}\""
for ((resu=1; resu<=ping_test_count; resu++));do
delay_object+=", \"$resu\": \"${pout[${key}1$1$resu]:-null}\""
done
delay_object+="},
            \"CU\": {
                \"Average\": \"${pavg[${key}2$1]:-null}\""
for ((resu=1; resu<=ping_test_count; resu++));do
delay_object+=", \"$resu\": \"${pout[${key}2$1$resu]:-null}\""
done
delay_object+="},
            \"CM\": {
                \"Average\": \"${pavg[${key}3$1]:-null}\""
for ((resu=1; resu<=ping_test_count; resu++));do
delay_object+=", \"$resu\": \"${pout[${key}3$1$resu]:-null}\""
done
delay_object+="}}"
delay_objects+=("$delay_object")
done
delay_array=$(printf '%s\n' "${delay_objects[@]}"|jq -s .)
netdata=$(echo "$netdata"|jq --argjson delay_array "$delay_array" '.Delay = $delay_array')
local transfer_object=()
local keys=($(echo "${!icity[@]}"|tr ' ' '\n'|sort -n))
for key in "${keys[@]}";do
transfer_object="{
            \"City\": \"${icity[$key]:-null}\",
            \"SendSpeed\": \"${isout[$key$11]:-null}\",
            \"SendRetransmits\": \"${isout[$key$12]:-null}\",
            \"ReceiveSpeed\": \"${isout[$key$13]:-null}\",
            \"ReceiveRetransmits\": \"${isout[$key$14]:-null}\",
            \"Delay\": {
                \"Average\": \"${iavg[$key]:-null}\""
for ((resu=1; resu<=10; resu++));do
transfer_object+=", \"$resu\": \"${ipout[$key$1$resu]:-null}\""
done
transfer_object+="}}"
netdata=$(echo "$netdata"|jq --argjson transfer_object "$transfer_object" '.Transfer += [$transfer_object]')
done
local speedtest_object=()
local keys=($(echo "${!scity[@]}"|tr ' ' '\n'|sort -n))
for key in "${keys[@]}";do
if [[ ${sout[${key}1]} -gt 0 || ${sout[${key}2]} -gt 0 || ${sout[${key}3]} -gt 0 || ${sout[${key}4]} -gt 0 ]];then
speedtest_object="{
                \"City\": \"${scity[$key]:-null}\",
                \"Provider\": \"${spv[$key]:-null}\",
                \"ID\": \"${sid[$key]:-null}\",
                \"SendSpeed\": \"${sout[${key}1]:-null}\",
                \"SendDelay\": \"${sout[${key}2]:-null}\",
                \"ReceiveSpeed\": \"${sout[${key}3]:-null}\",
                \"ReceiveDelay\": \"${sout[${key}4]:-null}\"
            }"
netdata=$(echo "$netdata"|jq --argjson speedtest_object "$speedtest_object" '.Speedtest += [$speedtest_object]')
fi
done
}
check_Net(){
IP=$1
ibar_step=0
netdata='{
      "Head": [{}],
      "BGP": [{}],
      "Local": [{}],
      "Connectivity": [],
      "Delay": [],
      "Speedtest": [],
      "Transfer": []
    }'
[[ $2 -eq 4 ]]&&hide_ipv4 $IP
[[ $2 -eq 6 ]]&&hide_ipv6 $IP
countRunTimes
[[ $mode_skip != *"1"* || $mode_skip != *"3"* ]]&&db_bgptools $2
[[ $mode_skip != *"1"* ]]&&db_henet $2
[[ $mode_skip != *"1"* && $2 -eq 4 && -n ${bgp[prefixnum]} ]]&&get_neighbor
getnat=()
[[ $mode_skip != *"2"* && $2 -eq 4 ]]&&get_nat
[[ $mode_skip != *"2"* ]]&&get_tcp
[[ $mode_skip != *"4"* ]]&&get_delay $2
[[ $mode_skip != *"5"* && $mode_route -eq 0 ]]&&get_route $2
[[ $mode_skip != *"5"* && $mode_route -eq 1 ]]&&get_route_mode $2
[[ $mode_skip != *"6"* && $2 -eq 4 ]]&&speedtest_test
[[ $mode_skip != *"7"* ]]&&iperf_test $2
echo -ne "$Font_LineClear" 1>&2
if [ $2 -eq 4 ]||[[ $IPV4work -eq 0 || $IPV4check -eq 0 ]];then
for ((i=0; i<ADLines; i++));do
echo -ne "$Font_LineUp" 1>&2
echo -ne "$Font_LineClear" 1>&2
done
fi
local net_report=$(show_head
[[ $mode_skip != *"1"* ]]&&show_bgp
[[ $mode_skip != *"2"* ]]&&show_local
[[ $mode_skip != *"3"* ]]&&show_conn
[[ $mode_skip != *"4"* ]]&&show_delay
[[ $mode_skip != *"5"* ]]&&show_route $2
[[ $mode_skip != *"6"* && $2 -eq 4 ]]&&show_speedtest
[[ $mode_skip != *"7"* ]]&&show_iperf
show_tail)
[[ mode_json -eq 1 || mode_output -eq 1 || mode_privacy -eq 0 ]]&&save_json $2
[[ mode_privacy -eq 0 ]]&&report_link=$(curl -$2 -s -X POST https://upload.check.place -d "type=net" --data-urlencode "json=$netdata" --data-urlencode "content=$net_report")
[[ mode_json -eq 0 ]]&&echo -ne "\r$net_report\n"
[[ mode_json -eq 0 && mode_privacy -eq 0 && $report_link == *"https://Report.Check.Place/"* ]]&&echo -ne "\r${stail[link]}$report_link$Font_Suffix\n"
[[ mode_json -eq 1 ]]&&echo -ne "\r$netdata\n"
echo -ne "\r\n"
if [[ mode_output -eq 1 ]];then
case "$outputfile" in
*.[aA][nN][sS][iI])echo "$net_report" >>"$outputfile" 2>/dev/null
;;
*.[jJ][sS][oO][nN])echo "$netdata" >>"$outputfile" 2>/dev/null
;;
*)echo -e "$net_report"|sed 's/\x1b\[[0-9;]*[mGKHF]//g' >>"$outputfile" 2>/dev/null
esac
fi
}
generate_random_user_agent
export LC_CTYPE=en_US.UTF-8 2>/dev/null
check_connectivity
get_ipv4
get_ipv6
is_valid_ipv4 $IPV4
is_valid_ipv6 $IPV6
get_opts "$@"
[[ mode_no -eq 0 ]]&&install_dependencies
set_language
read_ref
if [[ $ERRORcode -ne 0 ]];then
echo -ne "\r$Font_B$Font_Red${swarn[$ERRORcode]}$Font_Suffix\n"
exit $ERRORcode
fi
clear
show_ad
[[ $IPV4work -ne 0 && $IPV4check -ne 0 ]]&&check_Net "$IPV4" 4
[[ $IPV6work -ne 0 && $IPV6check -ne 0 ]]&&check_Net "$IPV6" 6
